浏览代码

1.3.0

1.新增 连连支付
2.支付宝同步alipay-sdk-NET-3.0.0
3....
Roc 7 年之前
父节点
当前提交
6299462022
共有 100 个文件被更改,包括 4561 次插入568 次删除
  1. 7 0
      Payment.sln
  2. 6 2
      README.MD
  3. 0 1
      samples/WebApplicationSample/Controllers/AlipayController.cs
  4. 4 3
      samples/WebApplicationSample/Controllers/JdPayController.cs
  5. 256 0
      samples/WebApplicationSample/Controllers/LianLianPayController.cs
  6. 80 3
      samples/WebApplicationSample/Controllers/NotifyController.cs
  7. 4 1
      samples/WebApplicationSample/Startup.cs
  8. 396 0
      samples/WebApplicationSample/Views/Home/Index.cshtml
  9. 1 0
      samples/WebApplicationSample/wwwroot/demo.js
  10. 24 10
      src/Essensoft.AspNetCore.Payment.Alipay/AlipayClient.cs
  11. 22 22
      src/Essensoft.AspNetCore.Payment.Alipay/AlipayNotifyClient.cs
  12. 1 1
      src/Essensoft.AspNetCore.Payment.Alipay/AlipayOptions.cs
  13. 0 28
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayDaoweiServicePriceModifyModel.cs
  14. 4 10
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayEcoEduKtBillingSendModel.cs
  15. 7 1
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayTradeAppPayModel.cs
  16. 10 4
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayTradeCreateModel.cs
  17. 10 4
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayTradePagePayModel.cs
  18. 8 2
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayTradePayModel.cs
  19. 9 3
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayTradePrecreateModel.cs
  20. 7 1
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayTradeWapPayModel.cs
  21. 3 3
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/ChargeItems.cs
  22. 39 2
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/DiscountInfo.cs
  23. 22 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/IndustryQualificationInfo.cs
  24. 22 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbPosBillDishDetail.cs
  25. 196 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbPosOrderDishDetail.cs
  26. 40 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishAreaFreeInfo.cs
  27. 83 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishAreaInfo.cs
  28. 59 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishCookDetailInfo.cs
  29. 131 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishCookInfo.cs
  30. 40 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishCookPriceInfo.cs
  31. 52 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishDictionary.cs
  32. 52 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishGroupDetailInfo.cs
  33. 71 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishGroupInfo.cs
  34. 149 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishInfo.cs
  35. 64 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishPackagesDetailInfo.cs
  36. 34 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishPracticeInfo.cs
  37. 101 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishSkuInfo.cs
  38. 64 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishTabInfo.cs
  39. 41 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/KoubeiCateringCommodityOrderBuyModel.cs
  40. 65 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/PosBillPayChannel.cs
  41. 40 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/PosDiscountDetail.cs
  42. 34 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/PosOrderKey.cs
  43. 64 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/SettleCardInfo.cs
  44. 34 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/SettleDetailInfo.cs
  45. 17 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/SettleInfo.cs
  46. 22 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/SimpleOperatorModel.cs
  47. 22 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/SimpleShopModel.cs
  48. 18 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/TemplateColumnInfoDTO.cs
  49. 18 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/TemplateStyleInfoDTO.cs
  50. 23 0
      src/Essensoft.AspNetCore.Payment.Alipay/Domain/VoucherDescDetailModel.cs
  51. 3 3
      src/Essensoft.AspNetCore.Payment.Alipay/Essensoft.AspNetCore.Payment.Alipay.csproj
  52. 13 120
      src/Essensoft.AspNetCore.Payment.Alipay/Parser/AlipayDictionaryParser.cs
  53. 0 42
      src/Essensoft.AspNetCore.Payment.Alipay/Parser/AlipayDictionaryReader.cs
  54. 212 0
      src/Essensoft.AspNetCore.Payment.Alipay/Parser/AlipayXmlParser.cs
  55. 4 4
      src/Essensoft.AspNetCore.Payment.Alipay/Request/KoubeiCateringCommodityOrderBuyRequest.cs
  56. 0 9
      src/Essensoft.AspNetCore.Payment.Alipay/Response/AlipayDaoweiServicePriceModifyResponse.cs
  57. 0 6
      src/Essensoft.AspNetCore.Payment.Alipay/Response/AlipayEcoEduKtBillingSendResponse.cs
  58. 12 0
      src/Essensoft.AspNetCore.Payment.Alipay/Response/AlipayTradeFastpayRefundQueryResponse.cs
  59. 35 0
      src/Essensoft.AspNetCore.Payment.Alipay/Response/KoubeiCateringCommodityOrderBuyResponse.cs
  60. 2 1
      src/Essensoft.AspNetCore.Payment.Alipay/Utility/AlipayEncrypt.cs
  61. 2 9
      src/Essensoft.AspNetCore.Payment.Alipay/Utility/AlipaySignature.cs
  62. 2 2
      src/Essensoft.AspNetCore.Payment.Alipay/Utility/AlipayUtility.cs
  63. 4 3
      src/Essensoft.AspNetCore.Payment.All/Essensoft.AspNetCore.Payment.All.csproj
  64. 0 1
      src/Essensoft.AspNetCore.Payment.JdPay/Domain/PayTradeVo.cs
  65. 3 3
      src/Essensoft.AspNetCore.Payment.JdPay/Essensoft.AspNetCore.Payment.JdPay.csproj
  66. 77 62
      src/Essensoft.AspNetCore.Payment.JdPay/JdPayClient.cs
  67. 62 62
      src/Essensoft.AspNetCore.Payment.JdPay/JdPayNotifyClient.cs
  68. 2 46
      src/Essensoft.AspNetCore.Payment.JdPay/JdPayNotifyResponse.cs
  69. 12 6
      src/Essensoft.AspNetCore.Payment.JdPay/JdPayResponse.cs
  70. 2 1
      src/Essensoft.AspNetCore.Payment.JdPay/Notify/JdPayAsyncNotifyResponse.cs
  71. 2 2
      src/Essensoft.AspNetCore.Payment.JdPay/Parser/IJdPayParser.cs
  72. 10 4
      src/Essensoft.AspNetCore.Payment.JdPay/Parser/JdPayDictionaryParser.cs
  73. 33 0
      src/Essensoft.AspNetCore.Payment.JdPay/Parser/JdPayXmlParser.cs
  74. 2 1
      src/Essensoft.AspNetCore.Payment.JdPay/Response/JdPayOrderQueryResponse.cs
  75. 2 10
      src/Essensoft.AspNetCore.Payment.JdPay/Utility/JdPaySignature.cs
  76. 55 11
      src/Essensoft.AspNetCore.Payment.JdPay/Utility/JdPayUtility.cs
  77. 0 59
      src/Essensoft.AspNetCore.Payment.JdPay/Utility/Utility.cs
  78. 46 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/Domain/Agreement.cs
  79. 58 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/Domain/SupportBank.cs
  80. 28 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/Essensoft.AspNetCore.Payment.LianLianPay.csproj
  81. 22 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/ILianLianPayClient.cs
  82. 33 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/ILianLianPayRequest.cs
  83. 192 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/LianLianPayClient.cs
  84. 65 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/LianLianPayDictionary.cs
  85. 105 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/LianLianPayNotifyClient.cs
  86. 6 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/LianLianPayNotifyResponse.cs
  87. 6 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/LianLianPayObject.cs
  88. 31 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/LianLianPayOptions.cs
  89. 19 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/LianLianPayResponse.cs
  90. 123 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/Notify/LianLianPayAuthPayNotifyResponse.cs
  91. 89 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/Notify/LianLianPayAuthPayReturnResponse.cs
  92. 89 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/Notify/LianLianPayBankPayNotifyResponse.cs
  93. 89 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/Notify/LianLianPayBankPayReturnResponse.cs
  94. 115 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/Notify/LianLianPayQuickPayNotifyResponse.cs
  95. 89 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/Notify/LianLianPayQuickPayReturnResponse.cs
  96. 70 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/Notify/LianLianPayRefundNotifyResponse.cs
  97. 16 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/Parser/ILianLianPayParser.cs
  98. 29 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/Parser/LianLianPayDictionaryParser.cs
  99. 39 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/Parser/LianLianPayJsonParser.cs
  100. 175 0
      src/Essensoft.AspNetCore.Payment.LianLianPay/Request/LianLianPayAuthPayRequest.cs

+ 7 - 0
Payment.sln

@@ -23,6 +23,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essensoft.AspNetCore.Paymen
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApplicationSample", "samples\WebApplicationSample\WebApplicationSample.csproj", "{07FED8BA-3825-43DE-BCA7-7C8B19F1AB76}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Essensoft.AspNetCore.Payment.LianLianPay", "src\Essensoft.AspNetCore.Payment.LianLianPay\Essensoft.AspNetCore.Payment.LianLianPay.csproj", "{16843D79-807F-4973-AF26-66FF7141BAAD}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -61,6 +63,10 @@ Global
 		{07FED8BA-3825-43DE-BCA7-7C8B19F1AB76}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{07FED8BA-3825-43DE-BCA7-7C8B19F1AB76}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{07FED8BA-3825-43DE-BCA7-7C8B19F1AB76}.Release|Any CPU.Build.0 = Release|Any CPU
+		{16843D79-807F-4973-AF26-66FF7141BAAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{16843D79-807F-4973-AF26-66FF7141BAAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{16843D79-807F-4973-AF26-66FF7141BAAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{16843D79-807F-4973-AF26-66FF7141BAAD}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -74,6 +80,7 @@ Global
 		{07AE45BF-9434-4254-A1ED-653300D48DDE} = {D3871E61-CA47-4BD0-8BF9-B64A42B2200D}
 		{66655C56-A98C-4F67-9F41-FECF0AFFA28E} = {D3871E61-CA47-4BD0-8BF9-B64A42B2200D}
 		{07FED8BA-3825-43DE-BCA7-7C8B19F1AB76} = {DD8CC860-F3E3-40F4-8A8F-20BF66EA051C}
+		{16843D79-807F-4973-AF26-66FF7141BAAD} = {D3871E61-CA47-4BD0-8BF9-B64A42B2200D}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {C5BE9B18-CD29-4490-84EA-68EDEEF75428}

+ 6 - 2
README.MD

@@ -4,13 +4,13 @@
 
 Package  | NuGet 
 -------- | :------------ 
-Essensoft.AspNetCore.Payment.All		| [![NuGet](https://img.shields.io/nuget/v/Essensoft.AspNetCore.Payment.All.svg)](https://www.nuget.org/packages/Essensoft.AspNetCore.Payment.All)
 Essensoft.AspNetCore.Payment.Alipay		| [![NuGet](https://img.shields.io/nuget/v/Essensoft.AspNetCore.Payment.Alipay.svg)](https://www.nuget.org/packages/Essensoft.AspNetCore.Payment.Alipay)
 Essensoft.AspNetCore.Payment.JdPay		| [![NuGet](https://img.shields.io/nuget/v/Essensoft.AspNetCore.Payment.JdPay.svg)](https://www.nuget.org/packages/Essensoft.AspNetCore.Payment.JdPay)
 Essensoft.AspNetCore.Payment.QPay		| [![NuGet](https://img.shields.io/nuget/v/Essensoft.AspNetCore.Payment.QPay.svg)](https://www.nuget.org/packages/Essensoft.AspNetCore.Payment.QPay)
 Essensoft.AspNetCore.Payment.Security		| [![NuGet](https://img.shields.io/nuget/v/Essensoft.AspNetCore.Payment.Security.svg)](https://www.nuget.org/packages/Essensoft.AspNetCore.Payment.Security)
 Essensoft.AspNetCore.Payment.UnionPay		| [![NuGet](https://img.shields.io/nuget/v/Essensoft.AspNetCore.Payment.UnionPay.svg)](https://www.nuget.org/packages/Essensoft.AspNetCore.Payment.UnionPay)
 Essensoft.AspNetCore.Payment.WeChatPay		| [![NuGet](https://img.shields.io/nuget/v/Essensoft.AspNetCore.Payment.WeChatPay.svg)](https://www.nuget.org/packages/Essensoft.AspNetCore.Payment.WeChatPay)
+Essensoft.AspNetCore.Payment.LianLianPay		| [![NuGet](https://img.shields.io/nuget/v/Essensoft.AspNetCore.Payment.LianLianPay.svg)](https://www.nuget.org/packages/Essensoft.AspNetCore.Payment.LianLianPay)
 
 ## 官方文档
 
@@ -28,7 +28,7 @@ Essensoft.AspNetCore.Payment.WeChatPay		| [![NuGet](https://img.shields.io/nuget
 
 ## 开发环境
 * Windows 10
-* VS2017 15.6.4
+* VS2017 15.6.5
 * .NET Core SDK 2.1.103
 
 ## 支持渠道
@@ -37,6 +37,10 @@ Essensoft.AspNetCore.Payment.WeChatPay		| [![NuGet](https://img.shields.io/nuget
 ## 使用方式
 见示例项目:WebApplicationSample</p>
 
+<p align="center">
+    <img src="http://p687qfgw0.bkt.clouddn.com/demo.png">
+</p>
+
 ----
 
 ## 支持/打赏

+ 0 - 1
samples/WebApplicationSample/Controllers/AlipayController.cs

@@ -96,7 +96,6 @@ namespace WebApplicationSample.Controllers
             return Ok(response.Body);
         }
 
-
         [HttpPost]
         public async Task<IActionResult> Query(string out_trade_no, string trade_no)
         {

+ 4 - 3
samples/WebApplicationSample/Controllers/JdPayController.cs

@@ -95,7 +95,7 @@ namespace WebApplicationSample.Controllers
         }
 
         [HttpPost]
-        public async Task<IActionResult> Refund(string tradeNum, string oTradeNum, long amount, string currency)
+        public async Task<IActionResult> Refund(string tradeNum, string oTradeNum, long amount, string currency, string notifyUrl)
         {
             var request = new JdPayRefundRequest()
             {
@@ -103,6 +103,7 @@ namespace WebApplicationSample.Controllers
                 OTradeNum = oTradeNum,
                 Amount = amount,
                 Currency = currency,
+                NotifyUrl = notifyUrl
             };
 
             var response = await _client.ExecuteAsync(request);
@@ -124,11 +125,11 @@ namespace WebApplicationSample.Controllers
 
         [HttpGet]  // h5 get
         [HttpPost] // pc post
-        public IActionResult Return()
+        public async Task<IActionResult> Return()
         {
             try
             {
-                var notify = _notifyClient.ExecuteAsync<JdPaySyncReturnResponse>(Request);
+                var notify = await _notifyClient.ExecuteAsync<JdPaySyncReturnResponse>(Request);
                 return Content("success", "text/plain");
             }
             catch

+ 256 - 0
samples/WebApplicationSample/Controllers/LianLianPayController.cs

@@ -0,0 +1,256 @@
+using Essensoft.AspNetCore.Payment.LianLianPay;
+using Essensoft.AspNetCore.Payment.LianLianPay.Notify;
+using Essensoft.AspNetCore.Payment.LianLianPay.Request;
+using Microsoft.AspNetCore.Mvc;
+using System.Threading.Tasks;
+
+namespace WebApplicationSample.Controllers
+{
+    public class LianLianPayController : Controller
+    {
+        private readonly LianLianPayClient _client = null;
+        private readonly LianLianPayNotifyClient _notifyClient = null;
+
+        public LianLianPayController(LianLianPayClient client, LianLianPayNotifyClient notifyClient)
+        {
+            _client = client;
+            _notifyClient = notifyClient;
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> QuickPay(string no_order, string dt_order, string money_order, string name_goods,
+            string user_id, string notify_url, string url_return, string bank_code, string pay_type, string no_agree, string risk_item,
+            string id_type, string id_no, string acct_name, string card_no)
+        {
+            var request = new LianLianPayQuickPayRequest()
+            {
+                NoOrder = no_order,
+                DtOrder = dt_order,
+                MoneyOrder = money_order,
+                NameGoods = name_goods,
+                UserId = user_id,
+                NotifyUrl = notify_url,
+                UrlReturn = url_return,
+                BankCode = bank_code,
+                PayType = pay_type,
+                NoAgree = no_agree,
+                RiskItem = risk_item,
+                IdType = id_type,
+                IdNo = id_no,
+                AcctName = acct_name,
+                CardNo = card_no,
+            };
+            var response = await _client.PageExecuteAsync(request, "GET");
+            return Redirect(response.Body);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> BankPay(string no_order, string dt_order, string money_order,
+            string name_goods, string user_id, string notify_url, string url_return, string risk_item)
+        {
+            var request = new LianLianPayBankPayRequest()
+            {
+                NoOrder = no_order,
+                DtOrder = dt_order,
+                MoneyOrder = money_order,
+                NameGoods = name_goods,
+                UserId = user_id,
+                NotifyUrl = notify_url,
+                UrlReturn = url_return,
+                RiskItem = risk_item,
+            };
+            var response = await _client.PageExecuteAsync(request, "GET");
+            return Redirect(response.Body);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> AuthPay(string no_order, string dt_order, string money_order, string name_goods, string user_id,
+            string notify_url, string url_return, string bank_code, string pay_type, string no_agree, string risk_item, string id_type, string id_no,
+            string acct_name, string card_no)
+        {
+            var request = new LianLianPayAuthPayRequest()
+            {
+                NoOrder = no_order,
+                DtOrder = dt_order,
+                MoneyOrder = money_order,
+                NameGoods = name_goods,
+                UserId = user_id,
+                NotifyUrl = notify_url,
+                UrlReturn = url_return,
+                BankCode = bank_code,
+                PayType = pay_type,
+                NoAgree = no_agree,
+                RiskItem = risk_item,
+                IdType = id_type,
+                IdNo = id_no,
+                AcctName = acct_name,
+                CardNo = card_no,
+            };
+            var response = await _client.PageExecuteAsync(request, "GET");
+            return Redirect(response.Body);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> OrderQuery(string no_order, string dt_order, string oid_paybill)
+        {
+            var request = new LianLianPayOrderQueryRequest()
+            {
+                NoOrder = no_order,
+                DtOrder = dt_order,
+                OidPayBill = oid_paybill
+            };
+            var response = await _client.ExecuteAsync(request);
+            return Content(response.Body);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> QueryBankCarBin(string card_no)
+        {
+            var request = new LianLianPayQueryBankCarBinRequest()
+            {
+                CardNo = card_no,
+            };
+            var response = await _client.ExecuteAsync(request);
+            return Content(response.Body);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> QueryBankCarBindList(string user_id, string offset)
+        {
+            var request = new LianLianPayQueryBankCarBindListRequest()
+            {
+                UserId = user_id,
+                Offset = offset,
+            };
+            var response = await _client.ExecuteAsync(request);
+            return Content(response.Body);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> BankCardUnbind(string user_id, string pay_type, string no_agree)
+        {
+            var request = new LianLianPayBankCardUnbindRequest()
+            {
+                UserId = user_id,
+                PayType = pay_type,
+                NoAgree = no_agree,
+            };
+            var response = await _client.ExecuteAsync(request);
+            return Content(response.Body);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> ModifyPhone(string user_id, string no_agree, string pay_type, string card_no, string bind_mob)
+        {
+            var request = new LianLianPayModifyPhoneRequest()
+            {
+                UserId = user_id,
+                NoAgree = no_agree,
+                PayType = pay_type,
+                CardNo = card_no,
+                BindMob = bind_mob
+            };
+            var response = await _client.ExecuteAsync(request);
+            return Content(response.Body);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> ModifyPhoneCheck(string user_id, string token, string verify_code)
+        {
+            var request = new LianLianPayModifyPhoneCheckRequest()
+            {
+                UserId = user_id,
+                Token = token,
+                VerifyCode = verify_code,
+            };
+            var response = await _client.ExecuteAsync(request);
+            return Content(response.Body);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> SupportBankQuery(string bank_code, string card_type, string product_type, string pay_chnl)
+        {
+            var request = new LianLianPaySupportBankQueryRequest()
+            {
+                BankCode = bank_code,
+                CardType = card_type,
+                ProductType = product_type,
+                PayChnl = pay_chnl
+            };
+            var response = await _client.ExecuteAsync(request);
+            return Content(response.Body);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> Refund(string no_refund, string dt_refund, string money_refund, string no_order, string dt_order, string oid_paybill, string notify_url)
+        {
+            var request = new LianLianPayRefundRequest()
+            {
+                NoRefund = no_refund,
+                DtRefund = dt_refund,
+                MoneyRefund = money_refund,
+                NoOrder = no_order,
+                DtOrder = dt_order,
+                OidPaybill = oid_paybill,
+                NotifyUrl = notify_url,
+            };
+            var response = await _client.ExecuteAsync(request);
+            return Content(response.Body);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> RefundQuery(string no_refund, string dt_refund, string oid_refundno)
+        {
+            var request = new LianLianPayRefundQueryRequest()
+            {
+                NoRefund = no_refund,
+                DtRefund = dt_refund,
+                OidRefundNo = oid_refundno,
+            };
+            var response = await _client.ExecuteAsync(request);
+            return Content(response.Body);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> BankPayReturn()
+        {
+            try
+            {
+                var notify = await _notifyClient.ExecuteAsync<LianLianPayBankPayReturnResponse>(Request);
+                return Content("success", "text/plain");
+            }
+            catch
+            {
+                return Content("error", "text/plain");
+            }
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> QuickPayReturn()
+        {
+            try
+            {
+                var notify = await _notifyClient.ExecuteAsync<LianLianPayQuickPayReturnResponse>(Request);
+                return Content("success", "text/plain");
+            }
+            catch
+            {
+                return Content("error", "text/plain");
+            }
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> AuthPayReturn()
+        {
+            try
+            {
+                var notify = await _notifyClient.ExecuteAsync<LianLianPayAuthPayReturnResponse>(Request);
+                return Content("success", "text/plain");
+            }
+            catch
+            {
+                return Content("error", "text/plain");
+            }
+        }
+    }
+}

+ 80 - 3
samples/WebApplicationSample/Controllers/NotifyController.cs

@@ -2,6 +2,8 @@
 using Essensoft.AspNetCore.Payment.Alipay.Notify;
 using Essensoft.AspNetCore.Payment.JdPay;
 using Essensoft.AspNetCore.Payment.JdPay.Notify;
+using Essensoft.AspNetCore.Payment.LianLianPay;
+using Essensoft.AspNetCore.Payment.LianLianPay.Notify;
 using Essensoft.AspNetCore.Payment.QPay;
 using Essensoft.AspNetCore.Payment.QPay.Notify;
 using Essensoft.AspNetCore.Payment.UnionPay;
@@ -140,7 +142,7 @@ namespace WebApplicationSample.Controllers
             try
             {
                 var notify = await _client.ExecuteAsync<WeChatPayUnifiedOrderNotifyResponse>(Request);
-                if (!notify.IsError)
+                if (notify.ReturnCode == "SUCCESS")
                 {
                     if (notify.ResultCode == "SUCCESS")
                     {
@@ -176,7 +178,7 @@ namespace WebApplicationSample.Controllers
             try
             {
                 var notify = await _client.ExecuteAsync<WeChatPayRefundNotifyResponse>(Request);
-                if (!notify.IsError)
+                if (notify.ReturnCode == "SUCCESS")
                 {
                     if (notify.RefundStatus == "SUCCESS")
                     {
@@ -211,7 +213,7 @@ namespace WebApplicationSample.Controllers
                 if ("SUCCESS" == notify.TradeState)
                 {
                     Console.WriteLine("OutTradeNo: " + notify.OutTradeNo);
-                    return Content("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>", "text/xml");
+                    return Content("<xml><return_code>SUCCESS</return_code></xml>", "text/xml");
                 }
                 return NoContent();
             }
@@ -477,4 +479,79 @@ namespace WebApplicationSample.Controllers
             }
         }
     }
+
+    [Route("notify/lianlianpay")]
+    public class LianLianPayNotifyController : Controller
+    {
+        private readonly LianLianPayNotifyClient _client = null;
+        public LianLianPayNotifyController(LianLianPayNotifyClient client)
+        {
+            _client = client;
+        }
+
+        [Route("quickpay")]
+        [HttpPost]
+        public async Task<IActionResult> QuickPay()
+        {
+            try
+            {
+                var notify = await _client.ExecuteAsync<LianLianPayQuickPayNotifyResponse>(Request);
+                Console.WriteLine("NoOrder: " + notify.NoOrder);
+                return Content("{\"ret_code\":\"0000\",\"ret_msg\":\"交易成功\"}", "application/json");
+            }
+            catch
+            {
+                return NoContent();
+            }
+        }
+
+        [Route("bankpay")]
+        [HttpPost]
+        public async Task<IActionResult> BankPay()
+        {
+            try
+            {
+                var notify = await _client.ExecuteAsync<LianLianPayBankPayNotifyResponse>(Request);
+                Console.WriteLine("NoOrder: " + notify.NoOrder);
+                return Content("{\"ret_code\":\"0000\",\"ret_msg\":\"交易成功\"}", "application/json");
+            }
+            catch
+            {
+                return NoContent();
+            }
+        }
+
+        [Route("authpay")]
+        [HttpPost]
+        public async Task<IActionResult> AuthPay()
+        {
+            try
+            {
+                var notify = await _client.ExecuteAsync<LianLianPayAuthPayNotifyResponse>(Request);
+                Console.WriteLine("NoOrder: " + notify.NoOrder);
+                return Content("{\"ret_code\":\"0000\",\"ret_msg\":\"交易成功\"}", "application/json");
+            }
+            catch
+            {
+                return NoContent();
+            }
+        }
+
+        [Route("refund")]
+        [HttpPost]
+        public async Task<IActionResult> Refund()
+        {
+            try
+            {
+                var notify = await _client.ExecuteAsync<LianLianPayRefundNotifyResponse>(Request);
+                Console.WriteLine("NoRefund: " + notify.NoRefund);
+                return Content("{\"ret_code\":\"0000\",\"ret_msg\":\"交易成功\"}", "application/json");
+            }
+            catch
+            {
+                return NoContent();
+            }
+        }
+    }
+
 }

+ 4 - 1
samples/WebApplicationSample/Startup.cs

@@ -1,5 +1,6 @@
 using Essensoft.AspNetCore.Payment.Alipay;
 using Essensoft.AspNetCore.Payment.JdPay;
+using Essensoft.AspNetCore.Payment.LianLianPay;
 using Essensoft.AspNetCore.Payment.QPay;
 using Essensoft.AspNetCore.Payment.UnionPay;
 using Essensoft.AspNetCore.Payment.WeChatPay;
@@ -38,12 +39,14 @@ namespace WebApplicationSample
             services.AddQPay();
             services.AddUnionPay();
             services.AddWeChatPay();
+            services.AddLianLianPay();
 
             services.Configure<AlipayOptions>(Configuration.GetSection("Alipay"));
             services.Configure<JdPayOptions>(Configuration.GetSection("JdPay"));
             services.Configure<QPayOptions>(Configuration.GetSection("QPay"));
             services.Configure<UnionPayOptions>(Configuration.GetSection("UnionPay"));
             services.Configure<WeChatPayOptions>(Configuration.GetSection("WeChatPay"));
+            services.Configure<LianLianPayOptions>(Configuration.GetSection("LianLianPay"));
 
             services.AddWebEncoders(opt =>
             {
@@ -76,7 +79,7 @@ namespace WebApplicationSample
             //    "EncryptCert": "xxx",
             //    "MiddleCert": "xxx",
             //    "RootCert": "xxx",
-            //    "SecureKey": "xxx",
+            //    "TestMode": "true",
             //  },
             //  "WeChatPay": {
             //    "AppId": "xxx",

+ 396 - 0
samples/WebApplicationSample/Views/Home/Index.cshtml

@@ -15,6 +15,7 @@
             <li><a href="#tabs-api-qpay">QQ钱包</a></li>
             <li><a href="#tabs-api-jdpay">京东支付</a></li>
             <li><a href="#tabs-api-unionpay">银联支付</a></li>
+            <li><a href="#tabs-api-lianlianpay">连连支付</a></li>
         </ul>
         <div id="tabs-api-1">
             <h3>支付平台 官方文档:</h3>
@@ -23,6 +24,7 @@
             <p>QQ钱包:<a href="https://qpay.qq.com/qpaywiki.shtml" target="_blank">开发文档</a>、<a href="http://kf.qq.com/product/qq_enterprise.html" target="_blank">帮助中心</a></p>
             <p>京东支付:<a href="http://payapi.jd.com/" target="_blank">开发文档</a></p>
             <p>银联支付:<a href="https://open.unionpay.com/ajweb/product" target="_blank">开放平台</a></p>
+            <p>连连支付:<a href="http://open.lianlianpay.com/" target="_blank">开放平台</a></p>
             <h3>Payment:</h3>
             <p>QQ交流群:<a target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=aac56c8f02f54893267d3ac90787c1794a7687f3c31a923812a36b67c4ee6271">522457525</a></p>
             <h3>使用方式</h3>
@@ -1145,6 +1147,10 @@
                             <label>currency:</label>
                             <input type="text" name="currency" value="CNY">
                         </p>
+                        <p>
+                            <label>notify_url:</label>
+                            <input type="text" name="notifyUrl" value="http://www.baidu.com/notify/jdpay">
+                        </p>
                         <p>
                             <label>&nbsp;</label>
                             <input type="submit" class="button" value="提交">
@@ -1684,6 +1690,396 @@
                 </div>
             </div>
         </div>
+        <div id="tabs-api-lianlianpay">
+            <div id="tabs-purchase-lianlianpay">
+                <ul>
+                    <li><a href="#tabs-purchase-1">快捷支付</a></li>
+                    <li><a href="#tabs-purchase-2">网银支付</a></li>
+                    <li><a href="#tabs-purchase-3">认证支付</a></li>
+                    <li><a href="#tabs-purchase-4">订单查询</a></li>
+                    <li><a href="#tabs-purchase-5">银行卡卡bin查询</a></li>
+                    <li><a href="#tabs-purchase-6">用户签约信息查询</a></li>
+                    <li><a href="#tabs-purchase-7">银行卡解约</a></li>
+                    <li><a href="#tabs-purchase-8">银行支持查询</a></li>
+                    <li><a href="#tabs-purchase-9">更换手机号申请</a></li>
+                    <li><a href="#tabs-purchase-10">更换手机号验证</a></li>
+                    <li><a href="#tabs-purchase-11">退款</a></li>
+                    <li><a href="#tabs-purchase-12">退款查询</a></li>
+                </ul>
+                <div id="tabs-purchase-1">
+                    <form class="api-form" asp-controller="LianLianPay" asp-action="QuickPay" method="post" target="_blank">
+                        <p>
+                            <label>no_order:</label>
+                            <input type="text" name="no_order" value="@DateTime.Now.ToString("yyyyMMddHHmmss")">
+                        </p>
+                        <p>
+                            <label>dt_order:</label>
+                            <input type="text" name="dt_order" value="@DateTime.Now.ToString("yyyyMMddHHmmss")">
+                        </p>
+                        <p>
+                            <label>money_order:</label>
+                            <input type="text" name="money_order" value="0.01">
+                        </p>
+                        <p>
+                            <label>name_goods:</label>
+                            <input type="text" name="name_goods" value="连连支付快捷支付测试">
+                        </p>
+                        <p>
+                            <label>user_id:</label>
+                            <input type="text" name="user_id" value="1080088">
+                        </p>
+                        <p>
+                            <label>notify_url:</label>
+                            <input type="text" name="notify_url" value="http://www.baidu.com/notify/lianlianpay/quickpay">
+                        </p>
+                        <p>
+                            <label>url_return:</label>
+                            <input type="text" name="url_return" value="http://www.baidu.com/lianlianpay/quickpayreturn">
+                        </p>
+                        <p>
+                            <label>bank_code:</label>
+                            <input type="text" name="bank_code" value="">
+                        </p>
+                        <p>
+                            <label>pay_type:</label>
+                            <input type="text" name="pay_type" value="2">
+                        </p>
+                        <p>
+                            <label>no_agree:</label>
+                            <input type="text" name="no_agree" value="">
+                        </p>
+                        <p>
+                            <label>risk_item:</label>
+                            <input type="text" name="risk_item" value='{"frms_ware_category":"1999","user_info_full_name":"你好"}'>
+                        </p>
+                        <p>
+                            <label>id_type:</label>
+                            <input type="text" name="id_type" value="0">
+                        </p>
+                        <p>
+                            <label>id_no:</label>
+                            <input type="text" name="id_no" value="">
+                        </p>
+                        <p>
+                            <label>acct_name:</label>
+                            <input type="text" name="acct_name" value="">
+                        </p>
+                        <p>
+                            <label>card_no:</label>
+                            <input type="text" name="card_no" value="">
+                        </p>
+                        <p>
+                            <label>&nbsp;</label>
+                            <input type="submit" class="button" value="提交">
+                        </p>
+                    </form>
+                </div>
+                <div id="tabs-purchase-2">
+                    <form class="api-form" asp-controller="LianLianPay" asp-action="BankPay" method="post" target="_blank">
+                        <p>
+                            <label>no_order:</label>
+                            <input type="text" name="no_order" value="@DateTime.Now.ToString("yyyyMMddHHmmss")">
+                        </p>
+                        <p>
+                            <label>dt_order:</label>
+                            <input type="text" name="dt_order" value="@DateTime.Now.ToString("yyyyMMddHHmmss")">
+                        </p>
+                        <p>
+                            <label>money_order:</label>
+                            <input type="text" name="money_order" value="0.01">
+                        </p>
+                        <p>
+                            <label>name_goods:</label>
+                            <input type="text" name="name_goods" value="连连支付网银支付测试">
+                        </p>
+                        <p>
+                            <label>user_id:</label>
+                            <input type="text" name="user_id" value="1080088">
+                        </p>
+                        <p>
+                            <label>notify_url:</label>
+                            <input type="text" name="notify_url" value="http://www.baidu.com/notify/lianlianpay/bankpay">
+                        </p>
+                        <p>
+                            <label>url_return:</label>
+                            <input type="text" name="url_return" value="http://www.baidu.com/lianlianpay/bankpayreturn">
+                        </p>
+                        <p>
+                            <label>risk_item:</label>
+                            <input type="text" name="risk_item" value='{"frms_ware_category":"1999","user_info_full_name":"你好"}'>
+                        </p>
+                        <p>
+                            <label>&nbsp;</label>
+                            <input type="submit" class="button" value="提交">
+                        </p>
+                    </form>
+                </div>
+                <div id="tabs-purchase-3">
+                    <form class="api-form" asp-controller="LianLianPay" asp-action="AuthPay" method="post" target="_blank">
+                        <p>
+                            <label>no_order:</label>
+                            <input type="text" name="no_order" value="@DateTime.Now.ToString("yyyyMMddHHmmss")">
+                        </p>
+                        <p>
+                            <label>dt_order:</label>
+                            <input type="text" name="dt_order" value="@DateTime.Now.ToString("yyyyMMddHHmmss")">
+                        </p>
+                        <p>
+                            <label>money_order:</label>
+                            <input type="text" name="money_order" value="0.01">
+                        </p>
+                        <p>
+                            <label>name_goods:</label>
+                            <input type="text" name="name_goods" value="连连支付认证支付测试">
+                        </p>
+                        <p>
+                            <label>user_id:</label>
+                            <input type="text" name="user_id" value="1080088">
+                        </p>
+                        <p>
+                            <label>notify_url:</label>
+                            <input type="text" name="notify_url" value="http://www.baidu.com/notify/lianlianpay/authpay">
+                        </p>
+                        <p>
+                            <label>url_return:</label>
+                            <input type="text" name="url_return" value="http://www.baidu.com/lianlianpay/authpayreturn">
+                        </p>
+                        <p>
+                            <label>bank_code:</label>
+                            <input type="text" name="bank_code" value="">
+                        </p>
+                        <p>
+                            <label>pay_type:</label>
+                            <input type="text" name="pay_type" value="D">
+                        </p>
+                        <p>
+                            <label>no_agree:</label>
+                            <input type="text" name="no_agree" value="">
+                        </p>
+                        <p>
+                            <label>risk_item:</label>
+                            <input type="text" name="risk_item" value='{"frms_ware_category":"1999","user_info_full_name":"你好"}'>
+                        </p>
+                        <p>
+                            <label>id_type:</label>
+                            <input type="text" name="id_type" value="0">
+                        </p>
+                        <p>
+                            <label>id_no:</label>
+                            <input type="text" name="id_no" value="">
+                        </p>
+                        <p>
+                            <label>acct_name:</label>
+                            <input type="text" name="acct_name" value="">
+                        </p>
+                        <p>
+                            <label>card_no:</label>
+                            <input type="text" name="card_no" value="">
+                        </p>
+                        <p>
+                            <label>&nbsp;</label>
+                            <input type="submit" class="button" value="提交">
+                        </p>
+                    </form>
+                </div>
+                <div id="tabs-purchase-4">
+                    <form class="api-form" asp-controller="LianLianPay" asp-action="OrderQuery" method="post" target="_blank">
+                        <p>
+                            <label>no_order:</label>
+                            <input type="text" name="no_order" value="@DateTime.Now.ToString("yyyyMMddHHmmss")">
+                        </p>
+                        <p>
+                            <label>dt_order:</label>
+                            <input type="text" name="dt_order" value="@DateTime.Now.ToString("yyyyMMddHHmmss")">
+                        </p>
+                        <p>
+                            <label>oid_paybill:</label>
+                            <input type="text" name="oid_paybill" value="">
+                        </p>
+                        <p>
+                            <label>&nbsp;</label>
+                            <input type="submit" class="button" value="提交">
+                        </p>
+                    </form>
+                </div>
+                <div id="tabs-purchase-5">
+                    <form class="api-form" asp-controller="LianLianPay" asp-action="QueryBankCarBin" method="post" target="_blank">
+                        <p>
+                            <label>card_no:</label>
+                            <input type="text" name="card_no" value="">
+                        </p>
+                        <p>
+                            <label>&nbsp;</label>
+                            <input type="submit" class="button" value="提交">
+                        </p>
+                    </form>
+                </div>
+                <div id="tabs-purchase-6">
+                    <form class="api-form" asp-controller="LianLianPay" asp-action="QueryBankCarBindList" method="post" target="_blank">
+                        <p>
+                            <label>user_id:</label>
+                            <input type="text" name="user_id" value="">
+                        </p>
+                        <p>
+                            <label>offset:</label>
+                            <input type="text" name="offset" value="">
+                        </p>
+                        <p>
+                            <label>&nbsp;</label>
+                            <input type="submit" class="button" value="提交">
+                        </p>
+                    </form>
+                </div>
+                <div id="tabs-purchase-7">
+                    <form class="api-form" asp-controller="LianLianPay" asp-action="BankCardUnbind" method="post" target="_blank">
+                        <p>
+                            <label>user_id:</label>
+                            <input type="text" name="user_id" value="">
+                        </p>
+                        <p>
+                            <label>pay_type:</label>
+                            <input type="text" name="pay_type" value="">
+                        </p>
+                        <p>
+                            <label>no_agree:</label>
+                            <input type="text" name="no_agree" value="">
+                        </p>
+                        <p>
+                            <label>&nbsp;</label>
+                            <input type="submit" class="button" value="提交">
+                        </p>
+                    </form>
+                </div>
+                <div id="tabs-purchase-8">
+                    <form class="api-form" asp-controller="LianLianPay" asp-action="SupportBankQuery" method="post" target="_blank">
+                        <p>
+                            <label>bank_code:</label>
+                            <input type="text" name="bank_code" value="">
+                        </p>
+                        <p>
+                            <label>card_type:</label>
+                            <input type="text" name="card_type" value="">
+                        </p>
+                        <p>
+                            <label>product_type:</label>
+                            <input type="text" name="product_type" value="">
+                        </p>
+                        <p>
+                            <label>pay_chnl:</label>
+                            <input type="text" name="pay_chnl" value="">
+                        </p>
+                        <p>
+                            <label>&nbsp;</label>
+                            <input type="submit" class="button" value="提交">
+                        </p>
+                    </form>
+                </div>
+                <div id="tabs-purchase-9">
+                    <form class="api-form" asp-controller="LianLianPay" asp-action="ModifyPhone" method="post" target="_blank">
+                        <p>
+                            <label>user_id:</label>
+                            <input type="text" name="user_id" value="">
+                        </p>
+                        <p>
+                            <label>no_agree:</label>
+                            <input type="text" name="no_agree" value="">
+                        </p>
+                        <p>
+                            <label>pay_type:</label>
+                            <input type="text" name="pay_type" value="">
+                        </p>
+                        <p>
+                            <label>card_no:</label>
+                            <input type="text" name="card_no" value="">
+                        </p>
+                        <p>
+                            <label>bind_mob:</label>
+                            <input type="text" name="bind_mob" value="">
+                        </p>
+                        <p>
+                            <label>&nbsp;</label>
+                            <input type="submit" class="button" value="提交">
+                        </p>
+                    </form>
+                </div>
+                <div id="tabs-purchase-10">
+                    <form class="api-form" asp-controller="LianLianPay" asp-action="ModifyPhoneCheck" method="post" target="_blank">
+                        <p>
+                            <label>user_id:</label>
+                            <input type="text" name="user_id" value="">
+                        </p>
+                        <p>
+                            <label>token:</label>
+                            <input type="text" name="token" value="">
+                        </p>
+                        <p>
+                            <label>verify_code:</label>
+                            <input type="text" name="verify_code" value="">
+                        </p>
+                        <p>
+                            <label>&nbsp;</label>
+                            <input type="submit" class="button" value="提交">
+                        </p>
+                    </form>
+                </div>
+                <div id="tabs-purchase-11">
+                    <form class="api-form" asp-controller="LianLianPay" asp-action="Refund" method="post" target="_blank">
+                        <p>
+                            <label>no_refund:</label>
+                            <input type="text" name="no_refund" value="@DateTime.Now.ToString("yyyyMMddHHmmss")">
+                        </p>
+                        <p>
+                            <label>dt_refund:</label>
+                            <input type="text" name="dt_refund" value="@DateTime.Now.ToString("yyyyMMddHHmmss")">
+                        </p>
+                        <p>
+                            <label>money_refund:</label>
+                            <input type="text" name="money_refund" value="0.01">
+                        </p>
+                        <p>
+                            <label>no_order:</label>
+                            <input type="text" name="no_order" value="">
+                        </p>
+                        <p>
+                            <label>dt_order:</label>
+                            <input type="text" name="dt_order" value="">
+                        </p>
+                        <p>
+                            <label>oid_paybill:</label>
+                            <input type="text" name="oid_paybill" value="">
+                        </p>
+                        <p>
+                            <label>notify_url:</label>
+                            <input type="text" name="notify_url" value="http://www.baidu.com/notify/lianlianpay/refund">
+                        </p>
+                        <p>
+                            <label>&nbsp;</label>
+                            <input type="submit" class="button" value="提交">
+                        </p>
+                    </form>
+                </div>
+                <div id="tabs-purchase-12">
+                    <form class="api-form" asp-controller="LianLianPay" asp-action="RefundQuery" method="post" target="_blank">
+                        <p>
+                            <label>no_refund:</label>
+                            <input type="text" name="no_refund" value="">
+                        </p>
+                        <p>
+                            <label>dt_refund:</label>
+                            <input type="text" name="dt_refund" value="">
+                        </p>
+                        <p>
+                            <label>oid_refundno:</label>
+                            <input type="text" name="oid_refundno" value="">
+                        </p>
+                        <p>
+                            <label>&nbsp;</label>
+                            <input type="submit" class="button" value="提交">
+                        </p>
+                    </form>
+                </div>
+            </div>
+        </div>
     </div>
 </div>
 

+ 1 - 0
samples/WebApplicationSample/wwwroot/demo.js

@@ -5,6 +5,7 @@ $(function () {
     setApiDemoTabs("#tabs-purchase-qpay");
     setApiDemoTabs("#tabs-purchase-jdpay");
     setApiDemoTabs("#tabs-purchase-unionpay");
+    setApiDemoTabs("#tabs-purchase-lianlianpay");
     $(document).tooltip();
 });
 

+ 24 - 10
src/Essensoft.AspNetCore.Payment.Alipay/AlipayClient.cs

@@ -141,10 +141,11 @@ namespace Essensoft.AspNetCore.Payment.Alipay
             };
 
             // 添加签名参数
-            txtParams.Add(SIGN, AlipaySignature.RSASign(txtParams, RSAPrivateParameters, Options.SignType));
+            var signContent = AlipaySignature.GetSignContent(txtParams);
+            txtParams.Add(SIGN, AlipaySignature.RSASignContent(signContent, RSAPrivateParameters, Options.SignType));
 
             // 是否需要上传文件
-            string body;
+            var body = string.Empty;
 
             if (request is IAlipayUploadRequest<T> uRequest)
             {
@@ -182,7 +183,12 @@ namespace Essensoft.AspNetCore.Payment.Alipay
 
             T rsp = null;
             IAlipayParser<T> parser = null;
-            if ("json".Equals(Options.Format))
+            if ("xml".Equals(Options.Format))
+            {
+                parser = new AlipayXmlParser<T>();
+                rsp = parser.Parse(body);
+            }
+            else
             {
                 parser = new AlipayJsonParser<T>();
                 rsp = parser.Parse(body);
@@ -260,10 +266,11 @@ namespace Essensoft.AspNetCore.Payment.Alipay
             }
 
             // 添加签名参数
-            txtParams.Add(SIGN, AlipaySignature.RSASign(txtParams, RSAPrivateParameters, Options.SignType));
+            var signContent = AlipaySignature.GetSignContent(txtParams);
+            txtParams.Add(SIGN, AlipaySignature.RSASignContent(signContent, RSAPrivateParameters, Options.SignType));
 
             var query = HttpClientEx.BuildQuery(txtParams);
-            Logger.LogInformation(0, "Request Content:{query}", query);
+            Logger.LogInformation(0, "Request:{query}", query);
 
             // 是否需要上传文件
             var body = string.Empty;
@@ -277,13 +284,19 @@ namespace Essensoft.AspNetCore.Payment.Alipay
                 body = await Client.DoPostAsync(Options.ServerUrl, query);
             }
 
-            Logger.LogInformation(1, "Response Content:{body}", body);
+            Logger.LogInformation(1, "Response:{body}", body);
 
             T rsp = null;
             IAlipayParser<T> parser = null;
-            if ("json".Equals(Options.Format))
+            if ("xml".Equals(Options.Format))
+            {
+                parser = new AlipayXmlParser<T>();
+                rsp = parser.Parse(body);
+            }
+            else
             {
                 parser = new AlipayJsonParser<T>();
+                rsp = parser.Parse(body);
             }
 
             var item = ParseRespItem(request, body, parser, Options.EncyptKey, Options.EncyptType);
@@ -357,7 +370,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay
             var dicPara = new Dictionary<string, string>(sParaTemp);
 
             var sbHtml = new StringBuilder();
-            sbHtml.Append("<form id='alipaysubmit' name='alipaysubmit' action='" + Options.ServerUrl + "?charset=" + Options.Charset +
+            sbHtml.Append("<form id='submit' name='submit' action='" + Options.ServerUrl + "?charset=" + Options.Charset +
                  "' method='" + strMethod + "' style='display:none;'>");
 
             foreach (var temp in dicPara)
@@ -366,7 +379,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay
             }
             sbHtml.Append("<input type='submit' style='display:none;'></form>");
             //表单实现自动提交
-            sbHtml.Append("<script>document.forms['alipaysubmit'].submit();</script>");
+            sbHtml.Append("<script>document.forms['submit'].submit();</script>");
 
             return sbHtml.ToString();
         }
@@ -384,7 +397,8 @@ namespace Essensoft.AspNetCore.Payment.Alipay
             var sortedAlipayDic = new AlipayDictionary(sortedParams);
 
             // 参数签名
-            var signResult = AlipaySignature.RSASign(sortedAlipayDic, RSAPrivateParameters, Options.SignType);
+            var signContent = AlipaySignature.GetSignContent(sortedAlipayDic);
+            var signResult = AlipaySignature.RSASignContent(signContent, RSAPrivateParameters, Options.SignType);
 
             // 添加签名结果参数
             sortedAlipayDic.Add(SIGN, signResult);

+ 22 - 22
src/Essensoft.AspNetCore.Payment.Alipay/AlipayNotifyClient.cs

@@ -34,25 +34,25 @@ namespace Essensoft.AspNetCore.Payment.Alipay
             RSAPublicParameters = AlipaySignature.GetPublicParameters(Options.RsaPublicKey);
         }
 
-        public Task<T> ExecuteAsync<T>(HttpRequest request) where T : AlipayNotifyResponse
+        public async Task<T> ExecuteAsync<T>(HttpRequest request) where T : AlipayNotifyResponse
         {
-            var parameters = GetParameters(request);
-            var parser = new AlipayDictionaryParser<T>();
-            var rsp = parser.Parse(parameters);
-
+            var parameters = await GetParametersAsync(request);
             var query = HttpClientEx.BuildQuery(parameters);
-            Logger.LogInformation(0, "Request Content:{query}", query);
+            Logger.LogInformation(0, "Request:{query}", query);
 
+            var parser = new AlipayDictionaryParser<T>();
+            var rsp = parser.Parse(parameters);
             CheckNotifySign(parameters, RSAPublicParameters, Options.SignType);
-            return Task.FromResult(rsp);
+            return rsp;
         }
 
-        private SortedDictionary<string, string> GetParameters(HttpRequest request)
+        private async Task<SortedDictionary<string, string>> GetParametersAsync(HttpRequest request)
         {
             var parameters = new SortedDictionary<string, string>();
             if (request.Method == "POST")
             {
-                foreach (var item in request.Form)
+                var form = await request.ReadFormAsync();
+                foreach (var item in form)
                 {
                     parameters.Add(item.Key, item.Value);
                 }
@@ -67,37 +67,37 @@ namespace Essensoft.AspNetCore.Payment.Alipay
             return parameters;
         }
 
-        private void CheckNotifySign(IDictionary<string, string> content, RSAParameters parameters, string signType)
+        private void CheckNotifySign(IDictionary<string, string> para, RSAParameters parameters, string signType)
         {
-            if (content.Count == 0)
+            if (para.Count == 0)
             {
                 throw new AlipayException("sign check fail: content is Empty!");
             }
 
-            var sign = content["sign"];
-            if (string.IsNullOrEmpty(sign))
+            if (!para.TryGetValue("sign", out var sign))
             {
                 throw new AlipayException("sign check fail: sign is Empty!");
             }
 
-            var prestr = GetSignContent(content);
+            var prestr = GetSignContent(para);
             if (!AlipaySignature.RSACheckContent(prestr, sign, parameters, signType))
             {
                 throw new AlipayException("sign check fail: check Sign and Data Fail JSON also");
             }
         }
 
-        private string GetSignContent(IDictionary<string, string> parameters)
+        private string GetSignContent(IDictionary<string, string> para)
         {
-            var content = new StringBuilder();
-            foreach (var iter in parameters)
+            if (para == null || para.Count == 0)
+                return string.Empty;
+
+            var sb = new StringBuilder();
+            foreach (var iter in para)
             {
-                if (iter.Key.ToLower() != "sign" && iter.Key.ToLower() != "sign_type" && !string.IsNullOrEmpty(iter.Value))
-                {
-                    content.Append(iter.Key + "=" + iter.Value + "&");
-                }
+                if (!string.IsNullOrEmpty(iter.Value) && iter.Key != "sign" && iter.Key != "sign_type")
+                    sb.Append(iter.Key).Append("=").Append(iter.Value).Append("&");
             }
-            return content.ToString().Substring(0, content.Length - 1);
+            return sb.Remove(sb.Length - 1, 1).ToString();
         }
     }
 }

+ 1 - 1
src/Essensoft.AspNetCore.Payment.Alipay/AlipayOptions.cs

@@ -23,7 +23,7 @@
         public string ServerUrl { get; set; } = "https://openapi.alipay.com/gateway.do";
 
         /// <summary>
-        /// 数据格式 仅支持JSON
+        /// 数据格式
         /// </summary>
         public string Format { get; set; } = "json";
 

+ 0 - 28
src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayDaoweiServicePriceModifyModel.cs

@@ -1,28 +0,0 @@
-using Newtonsoft.Json;
-
-namespace Essensoft.AspNetCore.Payment.Alipay.Domain
-{
-    /// <summary>
-    /// AlipayDaoweiServicePriceModifyModel Data Structure.
-    /// </summary>
-    public class AlipayDaoweiServicePriceModifyModel : AlipayObject
-    {
-        /// <summary>
-        /// 外部服务id,商家自己维护的唯一标识,用于确定商家的某个服务.仅支持数字,字母和下划线
-        /// </summary>
-        [JsonProperty("out_service_id")]
-        public string OutServiceId { get; set; }
-
-        /// <summary>
-        /// 价格维度类型,可选值:string;json。string表示unit_price的类型是一维价格,如果是json表示多维价格
-        /// </summary>
-        [JsonProperty("price_dim_type")]
-        public string PriceDimType { get; set; }
-
-        /// <summary>
-        /// 单价,单位为元,根据price_dim_type的值决定如果是一维价格直接使用字符串,比如:"30.5";如果是多维,需要跟SKU结合进行定价,SKU通过alipay.daowei.service.modify接口在创建服务的时候创建。例子:  [{out_sku_id: 1, price: 50.5},   {out_sku_id: 2, price: 60.5},  ]  out_sku_id是在sku中定义的外部商品库存单位信息ID,该配置表示out_sku_id为1的时候对应的价格是50.5,out_sku_id为2的时候对应的价格是60.5
-        /// </summary>
-        [JsonProperty("unit_price")]
-        public string UnitPrice { get; set; }
-    }
-}

+ 4 - 10
src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayEcoEduKtBillingSendModel.cs

@@ -9,7 +9,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
     public class AlipayEcoEduKtBillingSendModel : AlipayObject
     {
         /// <summary>
-        /// 总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]
+        /// 总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000],  如果是非多选项,是要和缴费项的总和相同,多选模式不做验证
         /// </summary>
         [JsonProperty("amount")]
         public string Amount { get; set; }
@@ -45,13 +45,13 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string ClassIn { get; set; }
 
         /// <summary>
-        /// 截止日期是否生效,与gmt_end_time发布配合使用,N为gmt_end_time不生效,用户过期后仍可以缴费;Y为gmt_end_time生效,用户过期后,不能再缴费。
+        /// 截止日期是否生效,与gmt_end发布配合使用,N为gmt_end不生效,用户过期后仍可以缴费;Y为gmt_end生效,用户过期后,不能再缴费。
         /// </summary>
         [JsonProperty("end_enable")]
         public string EndEnable { get; set; }
 
         /// <summary>
-        /// 缴费截止时间,格式"yyyy-MM-dd HH:mm:ss"
+        /// 缴费截止时间,格式"yyyy-MM-dd HH:mm:ss",日期要大于当前时间。请注意,过期时间不宜设置过短。
         /// </summary>
         [JsonProperty("gmt_end")]
         public string GmtEnd { get; set; }
@@ -87,13 +87,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string SchoolPid { get; set; }
 
         /// <summary>
-        /// 用于删除孩子,状态为“D”,表示删除孩子,状态“U”表示孩子信息添加或更新
-        /// </summary>
-        [JsonProperty("status")]
-        public string Status { get; set; }
-
-        /// <summary>
-        /// 学生的学号,一般以教育局学号为准,作为学生的唯一标识。此字段与student_identify、家长user_mobile至少选一个
+        /// 学生的学号,只支持字母和数字类型,一般以教育局学号为准,作为学生的唯一标识。此字段与student_identify、家长user_mobile至少选一个
         /// </summary>
         [JsonProperty("student_code")]
         public string StudentCode { get; set; }

+ 7 - 1
src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayTradeAppPayModel.cs

@@ -80,7 +80,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string PromoParams { get; set; }
 
         /// <summary>
-        /// 描述分账信息,Json格式,详见分账参数说明
+        /// 描述分账信息,json格式,详见分账参数说明
         /// </summary>
         [JsonProperty("royalty_info")]
         public RoyaltyInfo RoyaltyInfo { get; set; }
@@ -91,6 +91,12 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         [JsonProperty("seller_id")]
         public string SellerId { get; set; }
 
+        /// <summary>
+        /// 描述结算信息,json格式,详见结算参数说明
+        /// </summary>
+        [JsonProperty("settle_info")]
+        public SettleInfo SettleInfo { get; set; }
+
         /// <summary>
         /// 指定渠道,目前仅支持传入pcredit  若由于用户原因渠道不可用,用户可选择是否用其他渠道支付。  注:该参数不可与花呗分期参数同时传入
         /// </summary>

+ 10 - 4
src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayTradeCreateModel.cs

@@ -27,7 +27,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string BusinessParams { get; set; }
 
         /// <summary>
-        /// 买家的支付宝唯一用户号(2088开头的16位纯数字),和buyer_logon_id不能同时为空
+        /// 买家的支付宝唯一用户号(2088开头的16位纯数字)
         /// </summary>
         [JsonProperty("buyer_id")]
         public string BuyerId { get; set; }
@@ -39,7 +39,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string BuyerLogonId { get; set; }
 
         /// <summary>
-        /// 禁用渠道,用户不可用指定渠道支付  注,与enable_pay_channels互斥
+        /// 禁用渠道,用户不可用指定渠道支付,多个渠道以逗号分割  注,与enable_pay_channels互斥  <a href="https://docs.open.alipay.com/common/wifww7">渠道列表</a>
         /// </summary>
         [JsonProperty("disable_pay_channels")]
         public string DisablePayChannels { get; set; }
@@ -51,7 +51,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string DiscountableAmount { get; set; }
 
         /// <summary>
-        /// 可用渠道,用户只能在指定渠道范围内支付  注,与disable_pay_channels互斥
+        /// 可用渠道,用户只能在指定渠道范围内支付,多个渠道以逗号分割  注,与disable_pay_channels互斥  渠道列表:https://docs.open.alipay.com/common/wifww7
         /// </summary>
         [JsonProperty("enable_pay_channels")]
         public string EnablePayChannels { get; set; }
@@ -69,7 +69,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public ExtendParams ExtendParams { get; set; }
 
         /// <summary>
-        /// 订单包含的商品列表信息.Json格式.  其它说明详见:“商品明细说明”
+        /// 订单包含的商品列表信息,json格式,其它说明详见:“商品明细说明”
         /// </summary>
         [JsonProperty("goods_detail")]
         public List<GoodsDetail> GoodsDetail { get; set; }
@@ -104,6 +104,12 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         [JsonProperty("seller_id")]
         public string SellerId { get; set; }
 
+        /// <summary>
+        /// 描述结算信息,json格式,详见结算参数说明
+        /// </summary>
+        [JsonProperty("settle_info")]
+        public SettleInfo SettleInfo { get; set; }
+
         /// <summary>
         /// 商户门店编号
         /// </summary>

+ 10 - 4
src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayTradePagePayModel.cs

@@ -27,13 +27,13 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string BusinessParams { get; set; }
 
         /// <summary>
-        /// 禁用渠道,用户不可用指定渠道支付  注,与enable_pay_channels互斥
+        /// 禁用渠道,用户不可用指定渠道支付,多个渠道以逗号分割  注,与enable_pay_channels互斥  渠道列表:https://docs.open.alipay.com/common/wifww7
         /// </summary>
         [JsonProperty("disable_pay_channels")]
         public string DisablePayChannels { get; set; }
 
         /// <summary>
-        /// 可用渠道,用户只能在指定渠道范围内支付  注,与disable_pay_channels互斥
+        /// 可用渠道,用户只能在指定渠道范围内支付,多个渠道以逗号分割  注,与disable_pay_channels互斥  渠道列表:https://docs.open.alipay.com/common/wifww7
         /// </summary>
         [JsonProperty("enable_pay_channels")]
         public string EnablePayChannels { get; set; }
@@ -51,7 +51,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public ExtendParams ExtendParams { get; set; }
 
         /// <summary>
-        /// 订单包含的商品列表信息,Json格式,其它说明详见商品明细说明
+        /// 订单包含的商品列表信息,json格式,其它说明详见商品明细说明
         /// </summary>
         [JsonProperty("goods_detail")]
         public List<GoodsDetail> GoodsDetail { get; set; }
@@ -117,11 +117,17 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string RequestFromUrl { get; set; }
 
         /// <summary>
-        /// 描述分账信息,Json格式,详见分账参数说明
+        /// 描述分账信息,json格式,详见分账参数说明
         /// </summary>
         [JsonProperty("royalty_info")]
         public RoyaltyInfo RoyaltyInfo { get; set; }
 
+        /// <summary>
+        /// 描述结算信息,json格式,详见结算参数说明
+        /// </summary>
+        [JsonProperty("settle_info")]
+        public SettleInfo SettleInfo { get; set; }
+
         /// <summary>
         /// 商户门店编号
         /// </summary>

+ 8 - 2
src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayTradePayModel.cs

@@ -81,7 +81,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public ExtendParams ExtendParams { get; set; }
 
         /// <summary>
-        /// 订单包含的商品列表信息,Json格式,其它说明详见商品明细说明
+        /// 订单包含的商品列表信息,json格式,其它说明详见商品明细说明
         /// </summary>
         [JsonProperty("goods_detail")]
         public List<GoodsDetail> GoodsDetail { get; set; }
@@ -111,7 +111,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string ProductCode { get; set; }
 
         /// <summary>
-        /// 描述分账信息,Json格式,其它说明详见分账说明
+        /// 描述分账信息,json格式,其它说明详见分账说明
         /// </summary>
         [JsonProperty("royalty_info")]
         public RoyaltyInfo RoyaltyInfo { get; set; }
@@ -134,6 +134,12 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         [JsonProperty("settle_currency")]
         public string SettleCurrency { get; set; }
 
+        /// <summary>
+        /// 描述结算信息,json格式,详见结算参数说明
+        /// </summary>
+        [JsonProperty("settle_info")]
+        public SettleInfo SettleInfo { get; set; }
+
         /// <summary>
         /// 商户门店编号
         /// </summary>

+ 9 - 3
src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayTradePrecreateModel.cs

@@ -33,7 +33,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string BuyerLogonId { get; set; }
 
         /// <summary>
-        /// 禁用渠道,用户不可用指定渠道支付  当有多个渠道时用“,”分隔  注,与enable_pay_channels互斥
+        /// 禁用渠道,用户不可用指定渠道支付  当有多个渠道时用“,”分隔  注,与enable_pay_channels互斥  渠道列表:https://docs.open.alipay.com/common/wifww7
         /// </summary>
         [JsonProperty("disable_pay_channels")]
         public string DisablePayChannels { get; set; }
@@ -45,7 +45,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string DiscountableAmount { get; set; }
 
         /// <summary>
-        /// 可用渠道,用户只能在指定渠道范围内支付  当有多个渠道时用“,”分隔  注,与disable_pay_channels互斥
+        /// 可用渠道,用户只能在指定渠道范围内支付  当有多个渠道时用“,”分隔  注,与disable_pay_channels互斥  <a href="https://docs.open.alipay.com/common/wifww7">渠道列表</a>
         /// </summary>
         [JsonProperty("enable_pay_channels")]
         public string EnablePayChannels { get; set; }
@@ -63,7 +63,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public ExtendParams ExtendParams { get; set; }
 
         /// <summary>
-        /// 订单包含的商品列表信息.Json格式. 其它说明详见:“商品明细说明”
+        /// 订单包含的商品列表信息.json格式. 其它说明详见:“商品明细说明”
         /// </summary>
         [JsonProperty("goods_detail")]
         public List<GoodsDetail> GoodsDetail { get; set; }
@@ -98,6 +98,12 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         [JsonProperty("seller_id")]
         public string SellerId { get; set; }
 
+        /// <summary>
+        /// 描述结算信息,json格式,详见结算参数说明
+        /// </summary>
+        [JsonProperty("settle_info")]
+        public SettleInfo SettleInfo { get; set; }
+
         /// <summary>
         /// 商户门店编号
         /// </summary>

+ 7 - 1
src/Essensoft.AspNetCore.Payment.Alipay/Domain/AlipayTradeWapPayModel.cs

@@ -92,7 +92,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string QuitUrl { get; set; }
 
         /// <summary>
-        /// 描述分账信息,Json格式,详见分账参数说明
+        /// 描述分账信息,json格式,详见分账参数说明
         /// </summary>
         [JsonProperty("royalty_info")]
         public RoyaltyInfo RoyaltyInfo { get; set; }
@@ -103,6 +103,12 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         [JsonProperty("seller_id")]
         public string SellerId { get; set; }
 
+        /// <summary>
+        /// 描述结算信息,json格式,详见结算参数说明
+        /// </summary>
+        [JsonProperty("settle_info")]
+        public SettleInfo SettleInfo { get; set; }
+
         /// <summary>
         /// 指定渠道,目前仅支持传入pcredit  若由于用户原因渠道不可用,用户可选择是否用其他渠道支付。  注:该参数不可与花呗分期参数同时传入
         /// </summary>

+ 3 - 3
src/Essensoft.AspNetCore.Payment.Alipay/Domain/ChargeItems.cs

@@ -14,10 +14,10 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string ItemMandatory { get; set; }
 
         /// <summary>
-        /// 缴费项最大可选数  如果缴费项是多选模式,此参数生效,范围是1-9
+        /// 缴费项最大可选数  如果缴费项是多选模式,此参数生效,范围是1-9,如果为空,则最大项默认为9
         /// </summary>
-        [JsonProperty("item_max_num")]
-        public long ItemMaxNum { get; set; }
+        [JsonProperty("item_maximum")]
+        public long ItemMaximum { get; set; }
 
         /// <summary>
         /// 缴费项名称

+ 39 - 2
src/Essensoft.AspNetCore.Payment.Alipay/Domain/DiscountInfo.cs

@@ -1,4 +1,5 @@
 using Newtonsoft.Json;
+using System.Collections.Generic;
 
 namespace Essensoft.AspNetCore.Payment.Alipay.Domain
 {
@@ -25,6 +26,12 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         [JsonProperty("discount")]
         public string Discount { get; set; }
 
+        /// <summary>
+        /// 优惠说明信息
+        /// </summary>
+        [JsonProperty("discount_notes")]
+        public List<VoucherDescDetailModel> DiscountNotes { get; set; }
+
         /// <summary>
         /// 最近店铺离当前用户的距离
         /// </summary>
@@ -32,7 +39,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string Distance { get; set; }
 
         /// <summary>
-        /// 优惠结束时间,同时也是优惠券停止发放的时间
+        /// 优惠券停止发放的时间,和发放的优惠券的有效期不同
         /// </summary>
         [JsonProperty("end_time")]
         public string EndTime { get; set; }
@@ -73,6 +80,12 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         [JsonProperty("per_price")]
         public string PerPrice { get; set; }
 
+        /// <summary>
+        /// 发券商户ID
+        /// </summary>
+        [JsonProperty("pid")]
+        public string Pid { get; set; }
+
         /// <summary>
         /// 当券类型是全场及单品代金券的时候,这个字段代表券面额;  当券类型是减至券的时候,这个字段代表减至到的金额
         /// </summary>
@@ -110,7 +123,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         public string Sold { get; set; }
 
         /// <summary>
-        /// 优惠开始时间,同时也是优惠券发放的开始时间
+        /// 优惠券发放的开始时间,和发放的优惠券的有效期不同
         /// </summary>
         [JsonProperty("start_time")]
         public string StartTime { get; set; }
@@ -133,6 +146,30 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         [JsonProperty("type")]
         public string Type { get; set; }
 
+        /// <summary>
+        /// 券相对有效期,券自领取或者购买起多长时间内有效,取值范围 7-360,单位天
+        /// </summary>
+        [JsonProperty("validity_period")]
+        public string ValidityPeriod { get; set; }
+
+        /// <summary>
+        /// 核销绝对有效期开始时间。自该时间点起,券可被核销。  注意:券的开始发放时段开始时间(gmt_start)不能晚于该时间。
+        /// </summary>
+        [JsonProperty("validity_period_range_from")]
+        public string ValidityPeriodRangeFrom { get; set; }
+
+        /// <summary>
+        /// 核销绝对有效期结束时间。自该时间点起,券无法继续被核销。
+        /// </summary>
+        [JsonProperty("validity_period_range_to")]
+        public string ValidityPeriodRangeTo { get; set; }
+
+        /// <summary>
+        /// 有效期类型。支持相对有效期及绝对有效期两种方式,  RELATIVE:相对有效期  FIXED:绝对有效期  相对有效期指领取或者自购买之日起XX天有效,绝对有效期指某一端固定时间内有效。
+        /// </summary>
+        [JsonProperty("validity_period_type")]
+        public string ValidityPeriodType { get; set; }
+
         /// <summary>
         /// 优惠券二级类型,  all_discount:全场折扣;  single_discount:单品折扣;  all_cash:全场代金;  single_cash:单品代金  mei_man_jian:每满减券
         /// </summary>

+ 22 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/IndustryQualificationInfo.cs

@@ -0,0 +1,22 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// IndustryQualificationInfo Data Structure.
+    /// </summary>
+    public class IndustryQualificationInfo : AlipayObject
+    {
+        /// <summary>
+        /// 商户行业资质图片。其值为使用ant.merchant.expand.indirect.image.upload上传图片得到的一串oss key
+        /// </summary>
+        [JsonProperty("industry_qualification_image")]
+        public string IndustryQualificationImage { get; set; }
+
+        /// <summary>
+        /// 商户行业资质类型,具体选值参见https://mif-pub.alipayobjects.com/QualificationType.xlsx
+        /// </summary>
+        [JsonProperty("industry_qualification_type")]
+        public string IndustryQualificationType { get; set; }
+    }
+}

+ 22 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbPosBillDishDetail.cs

@@ -0,0 +1,22 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbPosBillDishDetail Data Structure.
+    /// </summary>
+    public class KbPosBillDishDetail : AlipayObject
+    {
+        /// <summary>
+        /// pos本地订单菜明细流水号
+        /// </summary>
+        [JsonProperty("out_detail_no")]
+        public string OutDetailNo { get; set; }
+
+        /// <summary>
+        /// 优免分摊金额(包含内部和外部优惠),以元为单位,精度到分
+        /// </summary>
+        [JsonProperty("trans_amount")]
+        public string TransAmount { get; set; }
+    }
+}

+ 196 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbPosOrderDishDetail.cs

@@ -0,0 +1,196 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbPosOrderDishDetail Data Structure.
+    /// </summary>
+    public class KbPosOrderDishDetail : AlipayObject
+    {
+        /// <summary>
+        /// 改价(单价),以元为单位,精度到分
+        /// </summary>
+        [JsonProperty("change_price")]
+        public string ChangePrice { get; set; }
+
+        /// <summary>
+        /// 改价原因
+        /// </summary>
+        [JsonProperty("change_reason")]
+        public string ChangeReason { get; set; }
+
+        /// <summary>
+        /// 菜谱ID
+        /// </summary>
+        [JsonProperty("cook_id")]
+        public string CookId { get; set; }
+
+        /// <summary>
+        /// 菜谱版本号,用时间戳实现(示例:date.getTime())
+        /// </summary>
+        [JsonProperty("cook_version")]
+        public string CookVersion { get; set; }
+
+        /// <summary>
+        /// 是否可以享受优惠
+        /// </summary>
+        [JsonProperty("discountable")]
+        public bool Discountable { get; set; }
+
+        /// <summary>
+        /// 菜品ID
+        /// </summary>
+        [JsonProperty("dish_id")]
+        public string DishId { get; set; }
+
+        /// <summary>
+        /// 菜品名称
+        /// </summary>
+        [JsonProperty("dish_name")]
+        public string DishName { get; set; }
+
+        /// <summary>
+        /// 菜品数量,≥1
+        /// </summary>
+        [JsonProperty("dish_num")]
+        public long DishNum { get; set; }
+
+        /// <summary>
+        /// 菜品单位
+        /// </summary>
+        [JsonProperty("dish_unit")]
+        public string DishUnit { get; set; }
+
+        /// <summary>
+        /// 菜品明细版本号
+        /// </summary>
+        [JsonProperty("dish_version")]
+        public long DishVersion { get; set; }
+
+        /// <summary>
+        /// 扩展信息,json对象格式,key和value都为字符串
+        /// </summary>
+        [JsonProperty("ext_info")]
+        public string ExtInfo { get; set; }
+
+        /// <summary>
+        /// 是否改价
+        /// </summary>
+        [JsonProperty("has_change")]
+        public bool HasChange { get; set; }
+
+        /// <summary>
+        /// 是否是主明细,默认都是主明细。除了点套餐的时候,套餐本身这个菜作为主明细设置,套餐下的菜明细作为非主明细设置。
+        /// </summary>
+        [JsonProperty("main_flag")]
+        public bool MainFlag { get; set; }
+
+        /// <summary>
+        /// 主明细id,套餐下的菜品对应的主明细id
+        /// </summary>
+        [JsonProperty("main_out_detail_no")]
+        public string MainOutDetailNo { get; set; }
+
+        /// <summary>
+        /// 制作状态,取值约定:INIT-未制作,MAKE-已制作,SERVE-已上菜,REFUND-已退菜
+        /// </summary>
+        [JsonProperty("make_status")]
+        public string MakeStatus { get; set; }
+
+        /// <summary>
+        /// 会员价(单价),以元为单位,精度到分
+        /// </summary>
+        [JsonProperty("member_price")]
+        public string MemberPrice { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        [JsonProperty("memo")]
+        public string Memo { get; set; }
+
+        /// <summary>
+        /// 下单操作员ID
+        /// </summary>
+        [JsonProperty("operator")]
+        public string Operator { get; set; }
+
+        /// <summary>
+        /// 下单时间,格式yyyy-mm-dd hh:mm:ss
+        /// </summary>
+        [JsonProperty("order_time")]
+        public string OrderTime { get; set; }
+
+        /// <summary>
+        /// pos本地订单菜明细流水号
+        /// </summary>
+        [JsonProperty("out_detail_no")]
+        public string OutDetailNo { get; set; }
+
+        /// <summary>
+        /// 做法信息,格式按照:做法=做法加价(单价)。价格以元为单位,精度到分
+        /// </summary>
+        [JsonProperty("practice_info")]
+        public string PracticeInfo { get; set; }
+
+        /// <summary>
+        /// 做法合计加价(单价),以元为单位,精度到分
+        /// </summary>
+        [JsonProperty("practice_price")]
+        public string PracticePrice { get; set; }
+
+        /// <summary>
+        /// 退菜原因
+        /// </summary>
+        [JsonProperty("refund_reason")]
+        public string RefundReason { get; set; }
+
+        /// <summary>
+        /// 退菜时间,格式yyyy-mm-dd hh:mm:ss
+        /// </summary>
+        [JsonProperty("refund_time")]
+        public string RefundTime { get; set; }
+
+        /// <summary>
+        /// 催菜次数
+        /// </summary>
+        [JsonProperty("remind_time")]
+        public long RemindTime { get; set; }
+
+        /// <summary>
+        /// 售价(单价),以元为单位,精度到分
+        /// </summary>
+        [JsonProperty("sell_price")]
+        public string SellPrice { get; set; }
+
+        /// <summary>
+        /// 菜品skuId
+        /// </summary>
+        [JsonProperty("sku_id")]
+        public string SkuId { get; set; }
+
+        /// <summary>
+        /// 菜品点菜序号
+        /// </summary>
+        [JsonProperty("sort")]
+        public long Sort { get; set; }
+
+        /// <summary>
+        /// 规格中文名,没有规格时不需要填写
+        /// </summary>
+        [JsonProperty("spec_name")]
+        public string SpecName { get; set; }
+
+        /// <summary>
+        /// 用户身份标识:手机号码、userId等等。如果是支付宝扫码点菜的,就是用户userId
+        /// </summary>
+        [JsonProperty("user_identity")]
+        public string UserIdentity { get; set; }
+
+        /// <summary>
+        /// 叫起状态,取值约定:WAIT-等待叫起,UP-已叫起
+        /// </summary>
+        [JsonProperty("wake_status")]
+        public string WakeStatus { get; set; }
+    }
+}

+ 40 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishAreaFreeInfo.cs

@@ -0,0 +1,40 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbdishAreaFreeInfo Data Structure.
+    /// </summary>
+    public class KbdishAreaFreeInfo : AlipayObject
+    {
+        /// <summary>
+        /// 餐区id
+        /// </summary>
+        [JsonProperty("area_id")]
+        public string AreaId { get; set; }
+
+        /// <summary>
+        /// 份数
+        /// </summary>
+        [JsonProperty("count")]
+        public string Count { get; set; }
+
+        /// <summary>
+        /// 口碑菜品id
+        /// </summary>
+        [JsonProperty("dish_id")]
+        public string DishId { get; set; }
+
+        /// <summary>
+        /// sku_id
+        /// </summary>
+        [JsonProperty("dish_sku_id")]
+        public string DishSkuId { get; set; }
+
+        /// <summary>
+        /// open 启动 stop 停用
+        /// </summary>
+        [JsonProperty("status")]
+        public string Status { get; set; }
+    }
+}

+ 83 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishAreaInfo.cs

@@ -0,0 +1,83 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbdishAreaInfo Data Structure.
+    /// </summary>
+    public class KbdishAreaInfo : AlipayObject
+    {
+        /// <summary>
+        /// 餐区开台菜列表
+        /// </summary>
+        [JsonProperty("area_free_list")]
+        public List<KbdishAreaFreeInfo> AreaFreeList { get; set; }
+
+        /// <summary>
+        /// 餐区id
+        /// </summary>
+        [JsonProperty("area_id")]
+        public string AreaId { get; set; }
+
+        /// <summary>
+        /// 餐区名称
+        /// </summary>
+        [JsonProperty("area_name")]
+        public string AreaName { get; set; }
+
+        /// <summary>
+        /// 餐区排序序号
+        /// </summary>
+        [JsonProperty("area_sort")]
+        public string AreaSort { get; set; }
+
+        /// <summary>
+        /// 创建人
+        /// </summary>
+        [JsonProperty("create_user")]
+        public string CreateUser { get; set; }
+
+        /// <summary>
+        /// 餐区服务费
+        /// </summary>
+        [JsonProperty("fee_price")]
+        public string FeePrice { get; set; }
+
+        /// <summary>
+        /// 商家id
+        /// </summary>
+        [JsonProperty("merchant_id")]
+        public string MerchantId { get; set; }
+
+        /// <summary>
+        /// 门店id 支付宝的
+        /// </summary>
+        [JsonProperty("shop_id")]
+        public string ShopId { get; set; }
+
+        /// <summary>
+        /// open 启动 stop 停用
+        /// </summary>
+        [JsonProperty("status")]
+        public string Status { get; set; }
+
+        /// <summary>
+        /// 餐区的餐桌数量
+        /// </summary>
+        [JsonProperty("tab_count")]
+        public string TabCount { get; set; }
+
+        /// <summary>
+        /// 餐区下的餐台列表
+        /// </summary>
+        [JsonProperty("tab_list")]
+        public List<KbdishTabInfo> TabList { get; set; }
+
+        /// <summary>
+        /// 修改人
+        /// </summary>
+        [JsonProperty("update_user")]
+        public string UpdateUser { get; set; }
+    }
+}

+ 59 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishCookDetailInfo.cs

@@ -0,0 +1,59 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbdishCookDetailInfo Data Structure.
+    /// </summary>
+    public class KbdishCookDetailInfo : AlipayObject
+    {
+        /// <summary>
+        /// 菜谱大类
+        /// </summary>
+        [JsonProperty("catetory_big_id")]
+        public string CatetoryBigId { get; set; }
+
+        /// <summary>
+        /// 菜谱小类
+        /// </summary>
+        [JsonProperty("catetory_small_id")]
+        public string CatetorySmallId { get; set; }
+
+        /// <summary>
+        /// 菜谱id
+        /// </summary>
+        [JsonProperty("cook_id")]
+        public string CookId { get; set; }
+
+        /// <summary>
+        /// 菜品id
+        /// </summary>
+        [JsonProperty("dish_id")]
+        public string DishId { get; set; }
+
+        /// <summary>
+        /// 打标
+        /// </summary>
+        [JsonProperty("flag")]
+        public string Flag { get; set; }
+
+        /// <summary>
+        /// 价格明细
+        /// </summary>
+        [JsonProperty("kb_cook_sku_price_list")]
+        public List<KbdishCookPriceInfo> KbCookSkuPriceList { get; set; }
+
+        /// <summary>
+        /// 排序值
+        /// </summary>
+        [JsonProperty("sort")]
+        public string Sort { get; set; }
+
+        /// <summary>
+        /// 状态
+        /// </summary>
+        [JsonProperty("status")]
+        public string Status { get; set; }
+    }
+}

+ 131 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishCookInfo.cs

@@ -0,0 +1,131 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbdishCookInfo Data Structure.
+    /// </summary>
+    public class KbdishCookInfo : AlipayObject
+    {
+        /// <summary>
+        /// 区域
+        /// </summary>
+        [JsonProperty("area")]
+        public string Area { get; set; }
+
+        /// <summary>
+        /// 渠道    eatin堂食,takeout外卖,paipai 扫码
+        /// </summary>
+        [JsonProperty("cook_channel")]
+        public string CookChannel { get; set; }
+
+        /// <summary>
+        /// 扩展字典,json串
+        /// </summary>
+        [JsonProperty("cook_ext_content")]
+        public string CookExtContent { get; set; }
+
+        /// <summary>
+        /// 菜谱id
+        /// </summary>
+        [JsonProperty("cook_id")]
+        public string CookId { get; set; }
+
+        /// <summary>
+        /// 菜谱名称
+        /// </summary>
+        [JsonProperty("cook_name")]
+        public string CookName { get; set; }
+
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        [JsonProperty("cook_version")]
+        public string CookVersion { get; set; }
+
+        /// <summary>
+        /// 操作员
+        /// </summary>
+        [JsonProperty("create_user")]
+        public string CreateUser { get; set; }
+
+        /// <summary>
+        /// 时间区间日期结束
+        /// </summary>
+        [JsonProperty("end_date")]
+        public string EndDate { get; set; }
+
+        /// <summary>
+        /// 时间区间截止 闭区间
+        /// </summary>
+        [JsonProperty("end_time")]
+        public string EndTime { get; set; }
+
+        /// <summary>
+        /// 口碑菜谱明细
+        /// </summary>
+        [JsonProperty("kb_cook_detail_list")]
+        public List<KbdishCookDetailInfo> KbCookDetailList { get; set; }
+
+        /// <summary>
+        /// 商户id
+        /// </summary>
+        [JsonProperty("merchant_id")]
+        public string MerchantId { get; set; }
+
+        /// <summary>
+        /// 时间约束类型 forever:永久;  week:按周,每周周几 month:按月,每月几号
+        /// </summary>
+        [JsonProperty("period_type")]
+        public string PeriodType { get; set; }
+
+        /// <summary>
+        /// 时间控制值,如果选的week, 值 1,2,3,4 ; 如果选择month 1,11,31 ; 如果选择永久,为空
+        /// </summary>
+        [JsonProperty("period_value")]
+        public string PeriodValue { get; set; }
+
+        /// <summary>
+        /// 菜谱描述
+        /// </summary>
+        [JsonProperty("remarks")]
+        public string Remarks { get; set; }
+
+        /// <summary>
+        /// 门店列表
+        /// </summary>
+        [JsonProperty("shop_list")]
+        public List<string> ShopList { get; set; }
+
+        /// <summary>
+        /// yazuo,meituan,ele获取,新增的时候必输。
+        /// </summary>
+        [JsonProperty("source_from")]
+        public string SourceFrom { get; set; }
+
+        /// <summary>
+        /// 控制的日期区间开始
+        /// </summary>
+        [JsonProperty("start_date")]
+        public string StartDate { get; set; }
+
+        /// <summary>
+        /// 时间控制 到分  闭区间
+        /// </summary>
+        [JsonProperty("start_time")]
+        public string StartTime { get; set; }
+
+        /// <summary>
+        /// open 启动 stop 停用
+        /// </summary>
+        [JsonProperty("status")]
+        public string Status { get; set; }
+
+        /// <summary>
+        /// 操作员
+        /// </summary>
+        [JsonProperty("update_user")]
+        public string UpdateUser { get; set; }
+    }
+}

+ 40 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishCookPriceInfo.cs

@@ -0,0 +1,40 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbdishCookPriceInfo Data Structure.
+    /// </summary>
+    public class KbdishCookPriceInfo : AlipayObject
+    {
+        /// <summary>
+        /// 菜单id
+        /// </summary>
+        [JsonProperty("cook_id")]
+        public string CookId { get; set; }
+
+        /// <summary>
+        /// 菜品id
+        /// </summary>
+        [JsonProperty("dish_id")]
+        public string DishId { get; set; }
+
+        /// <summary>
+        /// 会员价
+        /// </summary>
+        [JsonProperty("member_price")]
+        public string MemberPrice { get; set; }
+
+        /// <summary>
+        /// 售卖价格
+        /// </summary>
+        [JsonProperty("sell_price")]
+        public string SellPrice { get; set; }
+
+        /// <summary>
+        /// skuid
+        /// </summary>
+        [JsonProperty("sku_id")]
+        public string SkuId { get; set; }
+    }
+}

+ 52 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishDictionary.cs

@@ -0,0 +1,52 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbdishDictionary Data Structure.
+    /// </summary>
+    public class KbdishDictionary : AlipayObject
+    {
+        /// <summary>
+        /// 商家门店的操作小二,创建数据的人
+        /// </summary>
+        [JsonProperty("create_user")]
+        public string CreateUser { get; set; }
+
+        /// <summary>
+        /// 字典的数据id
+        /// </summary>
+        [JsonProperty("dictionary_id")]
+        public string DictionaryId { get; set; }
+
+        /// <summary>
+        /// 字典的扩展json,根据不同的biz_type,设置商家的自定义字典表key以及value。如果字典类型为catetory, key:cateSort,cateType,level,parentCatetoryId ;如果字典类型为spec, key:specSort.
+        /// </summary>
+        [JsonProperty("ext_info")]
+        public string ExtInfo { get; set; }
+
+        /// <summary>
+        /// 商户的支付宝user_id. 商户授权后,isv能获得,这个是给isv点单用的必须要要明确的id
+        /// </summary>
+        [JsonProperty("merchant_id")]
+        public string MerchantId { get; set; }
+
+        /// <summary>
+        /// 字典名称. 商家自定义的字符串
+        /// </summary>
+        [JsonProperty("name")]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// open 启动 stop 停用
+        /// </summary>
+        [JsonProperty("status")]
+        public string Status { get; set; }
+
+        /// <summary>
+        /// 商户门店的操作小二,修改数据的人
+        /// </summary>
+        [JsonProperty("update_user")]
+        public string UpdateUser { get; set; }
+    }
+}

+ 52 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishGroupDetailInfo.cs

@@ -0,0 +1,52 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbdishGroupDetailInfo Data Structure.
+    /// </summary>
+    public class KbdishGroupDetailInfo : AlipayObject
+    {
+        /// <summary>
+        /// 组下明细的加价单价 例如加2元 加3元
+        /// </summary>
+        [JsonProperty("add_price")]
+        public string AddPrice { get; set; }
+
+        /// <summary>
+        /// 明细菜品在套餐里的个数,
+        /// </summary>
+        [JsonProperty("detail_count")]
+        public string DetailCount { get; set; }
+
+        /// <summary>
+        /// 菜品id
+        /// </summary>
+        [JsonProperty("detail_dish_id")]
+        public string DetailDishId { get; set; }
+
+        /// <summary>
+        /// 组下面的菜品是否默认 Y/N
+        /// </summary>
+        [JsonProperty("detail_is_default")]
+        public string DetailIsDefault { get; set; }
+
+        /// <summary>
+        /// 分组下包含的明细菜品的dish_code
+        /// </summary>
+        [JsonProperty("detail_sku_id")]
+        public string DetailSkuId { get; set; }
+
+        /// <summary>
+        /// 排序字典
+        /// </summary>
+        [JsonProperty("detail_sort")]
+        public string DetailSort { get; set; }
+
+        /// <summary>
+        /// 组id
+        /// </summary>
+        [JsonProperty("group_id")]
+        public string GroupId { get; set; }
+    }
+}

+ 71 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishGroupInfo.cs

@@ -0,0 +1,71 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbdishGroupInfo Data Structure.
+    /// </summary>
+    public class KbdishGroupInfo : AlipayObject
+    {
+        /// <summary>
+        /// 操作员
+        /// </summary>
+        [JsonProperty("create_user")]
+        public string CreateUser { get; set; }
+
+        /// <summary>
+        /// 套餐组明细
+        /// </summary>
+        [JsonProperty("detail_list")]
+        public List<KbdishGroupDetailInfo> DetailList { get; set; }
+
+        /// <summary>
+        /// 组id
+        /// </summary>
+        [JsonProperty("group_id")]
+        public string GroupId { get; set; }
+
+        /// <summary>
+        /// 组名称
+        /// </summary>
+        [JsonProperty("group_name")]
+        public string GroupName { get; set; }
+
+        /// <summary>
+        /// 预留字段
+        /// </summary>
+        [JsonProperty("group_rule")]
+        public string GroupRule { get; set; }
+
+        /// <summary>
+        /// 版本号 就是一个数据操作的时间戳
+        /// </summary>
+        [JsonProperty("group_version")]
+        public string GroupVersion { get; set; }
+
+        /// <summary>
+        /// 商户id
+        /// </summary>
+        [JsonProperty("merchant_id")]
+        public string MerchantId { get; set; }
+
+        /// <summary>
+        /// open 启动 stop 停用
+        /// </summary>
+        [JsonProperty("status")]
+        public string Status { get; set; }
+
+        /// <summary>
+        /// 份数限制
+        /// </summary>
+        [JsonProperty("unit_count_limit")]
+        public string UnitCountLimit { get; set; }
+
+        /// <summary>
+        /// 修改操作小二
+        /// </summary>
+        [JsonProperty("update_user")]
+        public string UpdateUser { get; set; }
+    }
+}

+ 149 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishInfo.cs

@@ -0,0 +1,149 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbdishInfo Data Structure.
+    /// </summary>
+    public class KbdishInfo : AlipayObject
+    {
+        /// <summary>
+        /// 分类字典大类的id
+        /// </summary>
+        [JsonProperty("catetory_big_id")]
+        public string CatetoryBigId { get; set; }
+
+        /// <summary>
+        /// 小类,商家自定义配置表例如 肉,酒水,素菜
+        /// </summary>
+        [JsonProperty("catetory_small_id")]
+        public string CatetorySmallId { get; set; }
+
+        /// <summary>
+        /// 操作员
+        /// </summary>
+        [JsonProperty("create_user")]
+        public string CreateUser { get; set; }
+
+        /// <summary>
+        /// 是否是价 Y:是 N否
+        /// </summary>
+        [JsonProperty("cur_price_flag")]
+        public string CurPriceFlag { get; set; }
+
+        /// <summary>
+        /// 菜系,商家自定义
+        /// </summary>
+        [JsonProperty("dish_cuisine")]
+        public string DishCuisine { get; set; }
+
+        /// <summary>
+        /// 口碑的菜品id,新增的时候可以为空
+        /// </summary>
+        [JsonProperty("dish_id")]
+        public string DishId { get; set; }
+
+        /// <summary>
+        /// 商品图片,需要先调用素材的图片上传api得到图片id
+        /// </summary>
+        [JsonProperty("dish_img")]
+        public string DishImg { get; set; }
+
+        /// <summary>
+        /// 菜品的名称
+        /// </summary>
+        [JsonProperty("dish_name")]
+        public string DishName { get; set; }
+
+        /// <summary>
+        /// 做法加价列表
+        /// </summary>
+        [JsonProperty("dish_practice_list")]
+        public List<KbdishPracticeInfo> DishPracticeList { get; set; }
+
+        /// <summary>
+        /// 菜品sku列表
+        /// </summary>
+        [JsonProperty("dish_sku_list")]
+        public List<KbdishSkuInfo> DishSkuList { get; set; }
+
+        /// <summary>
+        /// 版本号 就是一个数据操作的时间戳
+        /// </summary>
+        [JsonProperty("dish_version")]
+        public string DishVersion { get; set; }
+
+        /// <summary>
+        /// 拼音助记码
+        /// </summary>
+        [JsonProperty("en_remember_code")]
+        public string EnRememberCode { get; set; }
+
+        /// <summary>
+        /// 扩展字段,json串
+        /// </summary>
+        [JsonProperty("ext_content")]
+        public string ExtContent { get; set; }
+
+        /// <summary>
+        /// 口碑的商品id,用于营销透传
+        /// </summary>
+        [JsonProperty("goods_id")]
+        public string GoodsId { get; set; }
+
+        /// <summary>
+        /// 商家id
+        /// </summary>
+        [JsonProperty("merchant_id")]
+        public string MerchantId { get; set; }
+
+        /// <summary>
+        /// 起点分数
+        /// </summary>
+        [JsonProperty("min_serving")]
+        public string MinServing { get; set; }
+
+        /// <summary>
+        /// 数字助记码
+        /// </summary>
+        [JsonProperty("nb_remember_code")]
+        public string NbRememberCode { get; set; }
+
+        /// <summary>
+        /// 菜品的描述
+        /// </summary>
+        [JsonProperty("remarks")]
+        public string Remarks { get; set; }
+
+        /// <summary>
+        /// open 启动 stop 停用
+        /// </summary>
+        [JsonProperty("status")]
+        public string Status { get; set; }
+
+        /// <summary>
+        /// 口碑枚举定义 single:单品;packages:套餐
+        /// </summary>
+        [JsonProperty("type_big")]
+        public string TypeBig { get; set; }
+
+        /// <summary>
+        /// 小类,口碑枚举定义 fixed:固定套餐;choose:选N套餐 几选几
+        /// </summary>
+        [JsonProperty("type_small")]
+        public string TypeSmall { get; set; }
+
+        /// <summary>
+        /// 单位id 字典的id
+        /// </summary>
+        [JsonProperty("unit_id")]
+        public string UnitId { get; set; }
+
+        /// <summary>
+        /// 修改操作小二
+        /// </summary>
+        [JsonProperty("update_user")]
+        public string UpdateUser { get; set; }
+    }
+}

+ 64 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishPackagesDetailInfo.cs

@@ -0,0 +1,64 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbdishPackagesDetailInfo Data Structure.
+    /// </summary>
+    public class KbdishPackagesDetailInfo : AlipayObject
+    {
+        /// <summary>
+        /// 明细菜品在套餐里的个数, 不填默认为1
+        /// </summary>
+        [JsonProperty("detail_count")]
+        public string DetailCount { get; set; }
+
+        /// <summary>
+        /// 是否追加可选 Y .N  明细是否追加可选
+        /// </summary>
+        [JsonProperty("detail_is_select")]
+        public string DetailIsSelect { get; set; }
+
+        /// <summary>
+        /// 明细菜品的会员价格单价
+        /// </summary>
+        [JsonProperty("detail_member_price")]
+        public string DetailMemberPrice { get; set; }
+
+        /// <summary>
+        /// 明细菜品在套餐里的售卖单价
+        /// </summary>
+        [JsonProperty("detail_sell_price")]
+        public string DetailSellPrice { get; set; }
+
+        /// <summary>
+        /// 套餐明细的skuId
+        /// </summary>
+        [JsonProperty("detail_sku_id")]
+        public string DetailSkuId { get; set; }
+
+        /// <summary>
+        /// 排序字段 必输 仅为数字 越小排在前面
+        /// </summary>
+        [JsonProperty("detail_sort")]
+        public string DetailSort { get; set; }
+
+        /// <summary>
+        /// 明细的类型,dish:单品 还是 group:项目
+        /// </summary>
+        [JsonProperty("detail_type")]
+        public string DetailType { get; set; }
+
+        /// <summary>
+        /// 套餐组id,如果类型是group 必须要填groupId
+        /// </summary>
+        [JsonProperty("group_id")]
+        public string GroupId { get; set; }
+
+        /// <summary>
+        /// 套餐的sku_code
+        /// </summary>
+        [JsonProperty("packages_sku_id")]
+        public string PackagesSkuId { get; set; }
+    }
+}

+ 34 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishPracticeInfo.cs

@@ -0,0 +1,34 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbdishPracticeInfo Data Structure.
+    /// </summary>
+    public class KbdishPracticeInfo : AlipayObject
+    {
+        /// <summary>
+        /// 口碑的菜品id
+        /// </summary>
+        [JsonProperty("dish_id")]
+        public string DishId { get; set; }
+
+        /// <summary>
+        /// 加价类型  add:直接加 multiply:乘以系数
+        /// </summary>
+        [JsonProperty("increase_mode")]
+        public string IncreaseMode { get; set; }
+
+        /// <summary>
+        /// 加价金额
+        /// </summary>
+        [JsonProperty("increase_price")]
+        public string IncreasePrice { get; set; }
+
+        /// <summary>
+        /// 做法名称
+        /// </summary>
+        [JsonProperty("practice_name")]
+        public string PracticeName { get; set; }
+    }
+}

+ 101 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishSkuInfo.cs

@@ -0,0 +1,101 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbdishSkuInfo Data Structure.
+    /// </summary>
+    public class KbdishSkuInfo : AlipayObject
+    {
+        /// <summary>
+        /// 餐盒费用
+        /// </summary>
+        [JsonProperty("box_price")]
+        public string BoxPrice { get; set; }
+
+        /// <summary>
+        /// 口碑的菜品id,新增的时候可以为空
+        /// </summary>
+        [JsonProperty("dish_id")]
+        public string DishId { get; set; }
+
+        /// <summary>
+        /// 套餐明细list
+        /// </summary>
+        [JsonProperty("dish_packages_detail_list")]
+        public List<KbdishPackagesDetailInfo> DishPackagesDetailList { get; set; }
+
+        /// <summary>
+        /// 商品的skuId
+        /// </summary>
+        [JsonProperty("goods_sku_id")]
+        public string GoodsSkuId { get; set; }
+
+        /// <summary>
+        /// 会员价格
+        /// </summary>
+        [JsonProperty("member_price")]
+        public string MemberPrice { get; set; }
+
+        /// <summary>
+        /// 售卖价格
+        /// </summary>
+        [JsonProperty("sell_price")]
+        public string SellPrice { get; set; }
+
+        /// <summary>
+        /// sku的扩展字典,json字符串
+        /// </summary>
+        [JsonProperty("sku_ext_content")]
+        public string SkuExtContent { get; set; }
+
+        /// <summary>
+        /// sku的id 口碑生成
+        /// </summary>
+        [JsonProperty("sku_id")]
+        public string SkuId { get; set; }
+
+        /// <summary>
+        /// sku的排序字段
+        /// </summary>
+        [JsonProperty("sku_sort")]
+        public string SkuSort { get; set; }
+
+        /// <summary>
+        /// 规则id1
+        /// </summary>
+        [JsonProperty("spec_code_01")]
+        public string SpecCode01 { get; set; }
+
+        /// <summary>
+        /// 规格2
+        /// </summary>
+        [JsonProperty("spec_code_02")]
+        public string SpecCode02 { get; set; }
+
+        /// <summary>
+        /// 规格3
+        /// </summary>
+        [JsonProperty("spec_code_03")]
+        public string SpecCode03 { get; set; }
+
+        /// <summary>
+        /// 规格4
+        /// </summary>
+        [JsonProperty("spec_code_04")]
+        public string SpecCode04 { get; set; }
+
+        /// <summary>
+        /// 规格5
+        /// </summary>
+        [JsonProperty("spec_code_05")]
+        public string SpecCode05 { get; set; }
+
+        /// <summary>
+        /// open 启动 stop 停用  变更状态的时候必输入.新增时候如果不设置默认设置启动
+        /// </summary>
+        [JsonProperty("status")]
+        public string Status { get; set; }
+    }
+}

+ 64 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KbdishTabInfo.cs

@@ -0,0 +1,64 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KbdishTabInfo Data Structure.
+    /// </summary>
+    public class KbdishTabInfo : AlipayObject
+    {
+        /// <summary>
+        /// 餐台所属餐区的id
+        /// </summary>
+        [JsonProperty("area_id")]
+        public string AreaId { get; set; }
+
+        /// <summary>
+        /// 餐台创建人
+        /// </summary>
+        [JsonProperty("create_user")]
+        public string CreateUser { get; set; }
+
+        /// <summary>
+        /// 餐台服务费
+        /// </summary>
+        [JsonProperty("fee_price")]
+        public string FeePrice { get; set; }
+
+        /// <summary>
+        /// 餐台座位人数
+        /// </summary>
+        [JsonProperty("seat_count")]
+        public string SeatCount { get; set; }
+
+        /// <summary>
+        /// 餐台id
+        /// </summary>
+        [JsonProperty("tab_id")]
+        public string TabId { get; set; }
+
+        /// <summary>
+        /// 餐台名称
+        /// </summary>
+        [JsonProperty("tab_name")]
+        public string TabName { get; set; }
+
+        /// <summary>
+        /// 餐台序号
+        /// </summary>
+        [JsonProperty("tab_sort")]
+        public string TabSort { get; set; }
+
+        /// <summary>
+        /// 餐台状态 empty:空闲 hold:站位  clean:清扫
+        /// </summary>
+        [JsonProperty("tab_tstatus")]
+        public string TabTstatus { get; set; }
+
+        /// <summary>
+        /// 餐区修改人
+        /// </summary>
+        [JsonProperty("update_user")]
+        public string UpdateUser { get; set; }
+    }
+}

+ 41 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/KoubeiCateringCommodityOrderBuyModel.cs

@@ -0,0 +1,41 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// KoubeiCateringCommodityOrderBuyModel Data Structure.
+    /// </summary>
+    public class KoubeiCateringCommodityOrderBuyModel : AlipayObject
+    {
+        /// <summary>
+        /// 订购服务时订购人id(订购人是操作员的时候,agent_Id为操作员个人Id)
+        /// </summary>
+        [JsonProperty("agent_id")]
+        public string AgentId { get; set; }
+
+        /// <summary>
+        /// merchant:表示订购人是商户,此时agentId和consumerCardNo是同一个;  operator: 表示订购人是操作员,此时agentId为操作员id,consumerCardNo是该操作员对应的主账户
+        /// </summary>
+        [JsonProperty("agent_type")]
+        public string AgentType { get; set; }
+
+        /// <summary>
+        /// 订购服务时订购人的主账户
+        /// </summary>
+        [JsonProperty("consumer_card_no")]
+        public string ConsumerCardNo { get; set; }
+
+        /// <summary>
+        /// 订购的服务ID
+        /// </summary>
+        [JsonProperty("merchandise_id")]
+        public string MerchandiseId { get; set; }
+
+        /// <summary>
+        /// 需要订购插件的门店集合;不传是不订购任何门店,order_result返回false
+        /// </summary>
+        [JsonProperty("shop_ids")]
+        public List<string> ShopIds { get; set; }
+    }
+}

+ 65 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/PosBillPayChannel.cs

@@ -0,0 +1,65 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// PosBillPayChannel Data Structure.
+    /// </summary>
+    public class PosBillPayChannel : AlipayObject
+    {
+        /// <summary>
+        /// 支付渠道类型
+        /// </summary>
+        [JsonProperty("channel_type")]
+        public string ChannelType { get; set; }
+
+        /// <summary>
+        /// 账单支付渠道维度优惠明细
+        /// </summary>
+        [JsonProperty("discount_details")]
+        public List<PosDiscountDetail> DiscountDetails { get; set; }
+
+        /// <summary>
+        /// 扩展信息,json对象格式,key和value都为字符串
+        /// </summary>
+        [JsonProperty("ext_info")]
+        public string ExtInfo { get; set; }
+
+        /// <summary>
+        /// 收银员ID
+        /// </summary>
+        [JsonProperty("operator")]
+        public string Operator { get; set; }
+
+        /// <summary>
+        /// 外部支付订单号,唯一标识本次支付的requestID
+        /// </summary>
+        [JsonProperty("out_pay_no")]
+        public string OutPayNo { get; set; }
+
+        /// <summary>
+        /// 支付抵扣金额
+        /// </summary>
+        [JsonProperty("pay_amount")]
+        public string PayAmount { get; set; }
+
+        /// <summary>
+        /// 支付渠道本身自己的支付订单号
+        /// </summary>
+        [JsonProperty("pay_no")]
+        public string PayNo { get; set; }
+
+        /// <summary>
+        /// 支付实收金额
+        /// </summary>
+        [JsonProperty("receipt_amount")]
+        public string ReceiptAmount { get; set; }
+
+        /// <summary>
+        /// 用户身份标识:手机号码、userId等
+        /// </summary>
+        [JsonProperty("user_identity")]
+        public string UserIdentity { get; set; }
+    }
+}

+ 40 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/PosDiscountDetail.cs

@@ -0,0 +1,40 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// PosDiscountDetail Data Structure.
+    /// </summary>
+    public class PosDiscountDetail : AlipayObject
+    {
+        /// <summary>
+        /// 优惠名称
+        /// </summary>
+        [JsonProperty("discount_name")]
+        public string DiscountName { get; set; }
+
+        /// <summary>
+        /// 优惠类型
+        /// </summary>
+        [JsonProperty("discount_type")]
+        public string DiscountType { get; set; }
+
+        /// <summary>
+        /// 扩展信息,存储优惠的详细模型。json对象格式,key和value都为字符串
+        /// </summary>
+        [JsonProperty("ext_info")]
+        public string ExtInfo { get; set; }
+
+        /// <summary>
+        /// 商家出资优惠金额,以元为单位,精确到分
+        /// </summary>
+        [JsonProperty("mrt_discount")]
+        public string MrtDiscount { get; set; }
+
+        /// <summary>
+        /// 平台出资优惠金额,以元为单位,精确到分
+        /// </summary>
+        [JsonProperty("rt_discount")]
+        public string RtDiscount { get; set; }
+    }
+}

+ 34 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/PosOrderKey.cs

@@ -0,0 +1,34 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// PosOrderKey Data Structure.
+    /// </summary>
+    public class PosOrderKey : AlipayObject
+    {
+        /// <summary>
+        /// pos设备序列号
+        /// </summary>
+        [JsonProperty("dv_sn")]
+        public string DvSn { get; set; }
+
+        /// <summary>
+        /// 商户pid
+        /// </summary>
+        [JsonProperty("merchant_id")]
+        public string MerchantId { get; set; }
+
+        /// <summary>
+        /// 订单版本号
+        /// </summary>
+        [JsonProperty("order_version")]
+        public long OrderVersion { get; set; }
+
+        /// <summary>
+        /// pos本地的订单号,同一个商户下唯一标识一笔订单的编号。
+        /// </summary>
+        [JsonProperty("out_biz_no")]
+        public string OutBizNo { get; set; }
+    }
+}

+ 64 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/SettleCardInfo.cs

@@ -0,0 +1,64 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// SettleCardInfo Data Structure.
+    /// </summary>
+    public class SettleCardInfo : AlipayObject
+    {
+        /// <summary>
+        /// 开户支行名
+        /// </summary>
+        [JsonProperty("account_branch_name")]
+        public string AccountBranchName { get; set; }
+
+        /// <summary>
+        /// 卡户名
+        /// </summary>
+        [JsonProperty("account_holder_name")]
+        public string AccountHolderName { get; set; }
+
+        /// <summary>
+        /// 开户行所在地-市
+        /// </summary>
+        [JsonProperty("account_inst_city")]
+        public string AccountInstCity { get; set; }
+
+        /// <summary>
+        /// 开户行简称缩写
+        /// </summary>
+        [JsonProperty("account_inst_id")]
+        public string AccountInstId { get; set; }
+
+        /// <summary>
+        /// 银行名称
+        /// </summary>
+        [JsonProperty("account_inst_name")]
+        public string AccountInstName { get; set; }
+
+        /// <summary>
+        /// 开户行所在地-省
+        /// </summary>
+        [JsonProperty("account_inst_province")]
+        public string AccountInstProvince { get; set; }
+
+        /// <summary>
+        /// 银行卡号
+        /// </summary>
+        [JsonProperty("account_no")]
+        public string AccountNo { get; set; }
+
+        /// <summary>
+        /// 卡类型  借记卡-DC  信用卡-CC
+        /// </summary>
+        [JsonProperty("account_type")]
+        public string AccountType { get; set; }
+
+        /// <summary>
+        /// 账号使用类型  对公-01  对私-02
+        /// </summary>
+        [JsonProperty("usage_type")]
+        public string UsageType { get; set; }
+    }
+}

+ 34 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/SettleDetailInfo.cs

@@ -0,0 +1,34 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// SettleDetailInfo Data Structure.
+    /// </summary>
+    public class SettleDetailInfo : AlipayObject
+    {
+        /// <summary>
+        /// 结算的金额,单位为元。目前必须和交易金额相同
+        /// </summary>
+        [JsonProperty("amount")]
+        public long Amount { get; set; }
+
+        /// <summary>
+        /// 结算汇总维度,按照这个维度汇总成批次结算,由商户指定。    目前需要和结算收款方账户类型为cardSerialNo配合使用
+        /// </summary>
+        [JsonProperty("summary_dimension")]
+        public string SummaryDimension { get; set; }
+
+        /// <summary>
+        /// 结算收款方。当结算收款方类型是cardSerialNo时,本参数为用户在支付宝绑定的卡编号
+        /// </summary>
+        [JsonProperty("trans_in")]
+        public string TransIn { get; set; }
+
+        /// <summary>
+        /// 结算收款方的账户类型。    cardSerialNo:结算收款方的银行卡编号。    目前只支持cardSerialNo账户类型
+        /// </summary>
+        [JsonProperty("trans_in_type")]
+        public string TransInType { get; set; }
+    }
+}

+ 17 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/SettleInfo.cs

@@ -0,0 +1,17 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// SettleInfo Data Structure.
+    /// </summary>
+    public class SettleInfo : AlipayObject
+    {
+        /// <summary>
+        /// 结算详细信息,json数组,目前只支持一条。
+        /// </summary>
+        [JsonProperty("settle_detail_infos")]
+        public List<SettleDetailInfo> SettleDetailInfos { get; set; }
+    }
+}

+ 22 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/SimpleOperatorModel.cs

@@ -0,0 +1,22 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// SimpleOperatorModel Data Structure.
+    /// </summary>
+    public class SimpleOperatorModel : AlipayObject
+    {
+        /// <summary>
+        /// 操作员id
+        /// </summary>
+        [JsonProperty("operator_id")]
+        public string OperatorId { get; set; }
+
+        /// <summary>
+        /// 操作员类型,只区分收银员和非收银员  收银员为“RESTRICTED_CASHIER”,非收银员为“STANDARD_NORMAL”
+        /// </summary>
+        [JsonProperty("operator_type")]
+        public string OperatorType { get; set; }
+    }
+}

+ 22 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/SimpleShopModel.cs

@@ -0,0 +1,22 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// SimpleShopModel Data Structure.
+    /// </summary>
+    public class SimpleShopModel : AlipayObject
+    {
+        /// <summary>
+        /// 商户门店id
+        /// </summary>
+        [JsonProperty("shop_id")]
+        public string ShopId { get; set; }
+
+        /// <summary>
+        /// 商户门店名称
+        /// </summary>
+        [JsonProperty("shop_name")]
+        public string ShopName { get; set; }
+    }
+}

+ 18 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/TemplateColumnInfoDTO.cs

@@ -13,6 +13,18 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         [JsonProperty("code")]
         public string Code { get; set; }
 
+        /// <summary>
+        /// 若template_style_info.column_info_layout  的值为grid,此项为宫格项所属分组标题。可空。如果需要展示该项,还需支付宝内部进行特殊配置。
+        /// </summary>
+        [JsonProperty("group_title")]
+        public string GroupTitle { get; set; }
+
+        /// <summary>
+        /// 若template_style_info.column_info_layout  的值为grid,此项为宫格项的展示icon。通过接口(alipay.offline.material.image.upload)上传图片。
+        /// </summary>
+        [JsonProperty("icon_id")]
+        public string IconId { get; set; }
+
         /// <summary>
         /// 扩展信息
         /// </summary>
@@ -25,6 +37,12 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         [JsonProperty("operate_type")]
         public string OperateType { get; set; }
 
+        /// <summary>
+        /// 若template_style_info.column_info_layout  的值为grid,此项为宫格项标签。可空。
+        /// </summary>
+        [JsonProperty("tag")]
+        public string Tag { get; set; }
+
         /// <summary>
         /// 栏目的标题
         /// </summary>

+ 18 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/TemplateStyleInfoDTO.cs

@@ -14,6 +14,18 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         [JsonProperty("background_id")]
         public string BackgroundId { get; set; }
 
+        /// <summary>
+        /// banner图片地址。 通过接口(alipay.offline.material.image.upload)上传图片。
+        /// </summary>
+        [JsonProperty("banner_img_id")]
+        public string BannerImgId { get; set; }
+
+        /// <summary>
+        /// banner跳转地址。
+        /// </summary>
+        [JsonProperty("banner_url")]
+        public string BannerUrl { get; set; }
+
         /// <summary>
         /// 背景色
         /// </summary>
@@ -38,6 +50,12 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Domain
         [JsonProperty("color")]
         public string Color { get; set; }
 
+        /// <summary>
+        /// 栏位信息布局。目前只支持list(列表)或grid(宫格)形式。如果为空则默认为list。
+        /// </summary>
+        [JsonProperty("column_info_layout")]
+        public string ColumnInfoLayout { get; set; }
+
         /// <summary>
         /// 特色信息,用于领卡预览
         /// </summary>

+ 23 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Domain/VoucherDescDetailModel.cs

@@ -0,0 +1,23 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Domain
+{
+    /// <summary>
+    /// VoucherDescDetailModel Data Structure.
+    /// </summary>
+    public class VoucherDescDetailModel : AlipayObject
+    {
+        /// <summary>
+        /// 优惠的说明信息
+        /// </summary>
+        [JsonProperty("details")]
+        public List<string> Details { get; set; }
+
+        /// <summary>
+        /// 优惠的标题
+        /// </summary>
+        [JsonProperty("title")]
+        public string Title { get; set; }
+    }
+}

+ 3 - 3
src/Essensoft.AspNetCore.Payment.Alipay/Essensoft.AspNetCore.Payment.Alipay.csproj

@@ -6,9 +6,9 @@
     <Authors>Roc</Authors>
     <Company>Essensoft</Company>
     <Product>Payment</Product>
-    <Version>1.2.1</Version>
-    <AssemblyVersion>1.2.1.0</AssemblyVersion>
-    <FileVersion>1.2.1.0</FileVersion>
+    <Version>1.3.0</Version>
+    <AssemblyVersion>1.3.0.0</AssemblyVersion>
+    <FileVersion>1.3.0.0</FileVersion>
     <Copyright>© Essensoft 2018</Copyright>
     <PackageProjectUrl>https://github.com/Essensoft/Payment</PackageProjectUrl>
     <GeneratePackageOnBuild>true</GeneratePackageOnBuild>

+ 13 - 120
src/Essensoft.AspNetCore.Payment.Alipay/Parser/AlipayDictionaryParser.cs

@@ -1,136 +1,29 @@
-using System;
+using Newtonsoft.Json;
+using System;
 using System.Collections;
-using System.Collections.Generic;
-using System.Reflection;
-using Newtonsoft.Json;
 
 namespace Essensoft.AspNetCore.Payment.Alipay.Parser
 {
     public class AlipayDictionaryParser<T> where T : AlipayObject
     {
-        private static readonly Dictionary<string, Dictionary<string, AlipayAttribute>> attrs = new Dictionary<string, Dictionary<string, AlipayAttribute>>();
-
-        public T Parse(IDictionary parameters)
+        public T Parse(IDictionary dic)
         {
-            IAlipayReader reader = new AlipayDictionaryReader(parameters);
-            return (T)AlipayDictionaryConvert(reader, typeof(T));
-        }
+            if (dic == null || dic.Count == 0)
+                throw new ArgumentNullException(nameof(dic));
 
-        private static Dictionary<string, AlipayAttribute> GetAlipayAttributes(Type type)
-        {
-            var inc = attrs.TryGetValue(type.FullName, out var tas);
+            T rsp = null;
 
-            if (inc && tas != null) // 从缓存中获取类属性元数据
+            try
             {
-                return tas;
-            }
-            else // 创建新的类属性元数据缓存
-            {
-                tas = new Dictionary<string, AlipayAttribute>();
-            }
-
-            var pis = type.GetRuntimeProperties();
-            foreach (var pi in pis)
-            {
-                var ta = new AlipayAttribute()
-                {
-                    Method = pi.GetSetMethod()
-                };
-
-                // 获取对象属性名称
-                if (pi.GetCustomAttributes(typeof(JsonPropertyAttribute), true) is JsonPropertyAttribute[] xeas && xeas.Length > 0)
-                {
-                    ta.ItemName = xeas[0].PropertyName;
-                }
-
-                // 获取列表属性名称
-                //if (ta.ItemName == null)
-                //{
-                //    if (pi.GetCustomAttributes(typeof(JsonPropertyItemAttribute), true) is JsonPropertyItemAttribute[] xaias && xaias.Length > 0)
-                //    {
-                //        ta.ItemName = xaias[0].ElementName;
-                //    }
-                //    if (pi.GetCustomAttributes(typeof(JsonPropertyAttribute), true) is JsonPropertyAttribute[] xaas && xaas.Length > 0)
-                //    {
-                //        ta.ListName = xaas[0].ElementName;
-                //    }
-                //    if (ta.ListName == null)
-                //    {
-                //        continue;
-                //    }
-                //}
-
-                // 获取属性类型
-                if (pi.PropertyType.IsConstructedGenericType)
-                {
-                    var types = pi.PropertyType.GenericTypeArguments;
-                    ta.ListType = types[0];
-                }
-                else
-                {
-                    ta.ItemType = pi.PropertyType;
-                }
-
-                tas.Add(pi.Name + ta.ItemType + ta.ListType, ta);
+                var jsonText = JsonConvert.SerializeObject(dic);
+                rsp = JsonConvert.DeserializeObject<T>(jsonText);
             }
+            catch { }
 
-            attrs[type.FullName] = tas;
-            return tas;
-        }
-
-        protected static readonly DAlipayConvert AlipayDictionaryConvert = delegate (IAlipayReader reader, Type type)
-        {
-            object rsp = null;
-            var pas = GetAlipayAttributes(type);
-            foreach(var item in pas)
-            {
-                var ta = item.Value;
-                var itemName = ta.ItemName;
-                var listName = ta.ListName;
-
-                if (!reader.HasReturnField(itemName) && (string.IsNullOrEmpty(listName) || !reader.HasReturnField(listName)))
-                {
-                    continue;
-                }
-
-                object value = null;
-
-                if (typeof(string) == ta.ItemType)
-                {
-                    var tmp = reader.GetPrimitiveObject(itemName);
-                    if (tmp != null)
-                    {
-                        value = tmp.ToString();
-                    }
-                }
-                else if (typeof(long) == ta.ItemType)
-                {
-                    var tmp = reader.GetPrimitiveObject(itemName);
-                    if (tmp != null)
-                    {
-                        value = ((IConvertible)tmp).ToInt64(null);
-                    }
-                }
-                else if (typeof(bool) == ta.ItemType)
-                {
-                    value = reader.GetPrimitiveObject(itemName);
-                }
-                else
-                {
-                    value = reader.GetReferenceObject(itemName, ta.ItemType, AlipayDictionaryConvert);
-                }
-
-                if (value != null)
-                {
-                    if (rsp == null)
-                    {
-                        rsp = Activator.CreateInstance(type);
-                    }
-                    ta.Method.Invoke(rsp, new object[] { value });
-                }
-            }
+            if (rsp == null)
+                rsp = Activator.CreateInstance<T>();
 
             return rsp;
-        };
+        }
     }
 }

+ 0 - 42
src/Essensoft.AspNetCore.Payment.Alipay/Parser/AlipayDictionaryReader.cs

@@ -1,42 +0,0 @@
-using System;
-using System.Collections;
-
-namespace Essensoft.AspNetCore.Payment.Alipay.Parser
-{
-    public class AlipayDictionaryReader : IAlipayReader
-    {
-        private IDictionary dictionary;
-
-        public AlipayDictionaryReader(IDictionary dictionary)
-        {
-            this.dictionary = dictionary;
-        }
-
-        public bool HasReturnField(object name)
-        {
-            return dictionary.Contains(name);
-        }
-
-        public object GetPrimitiveObject(object name)
-        {
-            return dictionary[name];
-        }
-
-        public object GetReferenceObject(object name, Type type, DAlipayConvert convert)
-        {
-            if (dictionary[name] is IDictionary dict && dict.Count > 0)
-            {
-                return convert(new AlipayDictionaryReader(dict), type);
-            }
-            else
-            {
-                return null;
-            }
-        }
-
-        public IList GetListObjects(string listName, string itemName, Type type, DAlipayConvert convert)
-        {
-            throw new NotImplementedException();
-        }
-    }
-}

+ 212 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Parser/AlipayXmlParser.cs

@@ -0,0 +1,212 @@
+using Essensoft.AspNetCore.Payment.Alipay.Request;
+using Essensoft.AspNetCore.Payment.Alipay.Utility;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Xml.Serialization;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Parser
+{
+    /// <summary>
+    /// Alipay XML响应通用解释器。
+    /// </summary>
+    public class AlipayXmlParser<T> : IAlipayParser<T> where T : AlipayResponse
+    {
+        private static Regex regex = new Regex("<(\\w+?)[ >]", RegexOptions.Compiled);
+        private static Dictionary<string, XmlSerializer> parsers = new Dictionary<string, XmlSerializer>();
+
+        #region IAlipayParser<T> Members
+
+        public T Parse(string body)
+        {
+            var rootTagName = GetRootElement(body);
+
+            var inc = parsers.TryGetValue(rootTagName, out var serializer);
+            if (!inc || serializer == null)
+            {
+                var rootAttrs = new XmlAttributes()
+                {
+                    XmlRoot = new XmlRootAttribute(rootTagName)
+                };
+                var attrOvrs = new XmlAttributeOverrides();
+                attrOvrs.Add(typeof(T), rootAttrs);
+
+                serializer = new XmlSerializer(typeof(T), attrOvrs);
+                parsers[rootTagName] = serializer;
+            }
+
+            object obj = null;
+            using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(body)))
+            {
+                obj = serializer.Deserialize(stream);
+            }
+
+            var rsp = (T)obj;
+            if (rsp != null)
+            {
+                rsp.Body = body;
+            }
+            return rsp;
+        }
+
+
+        public SignItem GetSignItem(IAlipayRequest<T> request, string reponseBody)
+        {
+
+            if (string.IsNullOrEmpty(reponseBody))
+            {
+                return null;
+            }
+
+            var signItem = new SignItem();
+            var sign = GetSign(reponseBody);
+            signItem.Sign = sign;
+
+            var signSourceData = GetSignSourceData(request, reponseBody);
+            signItem.SignSourceDate = signSourceData;
+
+            return signItem;
+        }
+
+        #endregion
+
+        /// <summary>
+        /// 获取XML响应的根节点名称
+        /// </summary>
+        private string GetRootElement(string body)
+        {
+            var match = regex.Match(body);
+            if (match.Success)
+            {
+                return match.Groups[1].ToString();
+            }
+            else
+            {
+                throw new AlipayException("Invalid XML response format!");
+            }
+        }
+
+        private static string GetSign(string body)
+        {
+            var signNodeName = "<" + AlipayConstants.SIGN + ">";
+            var signEndNodeName = "</" + AlipayConstants.SIGN + ">";
+
+            var indexOfSignNode = body.IndexOf(signNodeName);
+            var indexOfSignEndNode = body.IndexOf(signEndNodeName);
+
+            if (indexOfSignNode < 0 || indexOfSignEndNode < 0)
+            {
+                return null;
+            }
+
+            //  签名
+            var startPos = indexOfSignNode + signNodeName.Length;
+            return body.Substring(startPos, indexOfSignEndNode - startPos);
+        }
+
+        private static string GetSignSourceData(IAlipayRequest<T> request, string body)
+        {
+            var rootNode = request.GetApiName().Replace(".", "_") + AlipayConstants.RESPONSE_SUFFIX;
+            var errorRootNode = AlipayConstants.ERROR_RESPONSE;
+
+            var indexOfRootNode = body.IndexOf(rootNode);
+            var indexOfErrorRoot = body.IndexOf(errorRootNode);
+
+            string result = null;
+            if (indexOfRootNode > 0)
+            {
+                result = ParseSignSourceData(body, rootNode, indexOfRootNode);
+            }
+            else if (indexOfErrorRoot > 0)
+            {
+                result = ParseSignSourceData(body, errorRootNode, indexOfErrorRoot);
+            }
+
+            return result;
+        }
+
+        private static string ParseSignSourceData(string body, string rootNode, int indexOfRootNode)
+        {
+
+            //  第一个字母+长度+>
+            var signDataStartIndex = indexOfRootNode + rootNode.Length + 1;
+            var indexOfSign = body.IndexOf("<" + AlipayConstants.SIGN);
+            if (indexOfSign < 0)
+            {
+                return null;
+            }
+
+            // 签名前减去
+            var signDataEndIndex = indexOfSign;
+
+            return body.Substring(signDataStartIndex, signDataEndIndex - signDataStartIndex);
+        }
+
+        public string EncryptSourceData(IAlipayRequest<T> request, string body, string encryptType, string encryptKey)
+        {
+            var item = ParseEncryptData(request, body);
+
+            var bodyIndexContent = body.Substring(0, item.startIndex);
+            var bodyEndContent = body.Substring(item.endIndex);
+            var encryptContent = AlipayEncrypt.AesDencrypt(encryptKey, item.encryptContent);
+
+            return bodyIndexContent + encryptContent + bodyEndContent;
+        }
+
+        private static EncryptParseItem ParseEncryptData(IAlipayRequest<T> request, string body)
+        {
+            var rootNode = request.GetApiName().Replace(".", "_") + AlipayConstants.RESPONSE_SUFFIX;
+            var errorRootNode = AlipayConstants.ERROR_RESPONSE;
+
+            var indexOfRootNode = body.IndexOf(rootNode);
+            var indexOfErrorRoot = body.IndexOf(errorRootNode);
+
+            EncryptParseItem result = null;
+            if (indexOfRootNode > 0)
+            {
+                result = ParseEncryptItem(body, rootNode, indexOfRootNode);
+            }
+            else if (indexOfErrorRoot > 0)
+            {
+                result = ParseEncryptItem(body, errorRootNode, indexOfErrorRoot);
+            }
+
+            return result;
+        }
+
+        private static EncryptParseItem ParseEncryptItem(string body, string rootNode, int indexOfRootNode)
+        {
+            //  第一个字母+长度+>
+            var signDataStartIndex = indexOfRootNode + rootNode.Length + 1;
+
+            var xmlStartNode = "<" + AlipayConstants.ENCRYPT_NODE_NAME + ">";
+            var xmlEndNode = "</" + AlipayConstants.ENCRYPT_NODE_NAME + ">";
+            var indexOfEncryptNode = body.IndexOf(xmlEndNode);
+
+            if (indexOfEncryptNode < 0)
+            {
+                var item = new EncryptParseItem()
+                {
+                    encryptContent = null,
+                    startIndex = 0,
+                    endIndex = 0
+                };
+                return item;
+            }
+
+            var startIndex = signDataStartIndex + xmlStartNode.Length;
+            var bizLen = indexOfEncryptNode - startIndex;
+
+            var encryptBizContent = body.Substring(startIndex, bizLen);
+
+            var item2 = new EncryptParseItem()
+            {
+                encryptContent = encryptBizContent,
+                startIndex = signDataStartIndex,
+                endIndex = indexOfEncryptNode + xmlEndNode.Length
+            };
+            return item2;
+        }
+    }
+}

+ 4 - 4
src/Essensoft.AspNetCore.Payment.Alipay/Request/AlipayDaoweiServicePriceModifyRequest.cs → src/Essensoft.AspNetCore.Payment.Alipay/Request/KoubeiCateringCommodityOrderBuyRequest.cs

@@ -4,12 +4,12 @@ using Essensoft.AspNetCore.Payment.Alipay.Response;
 namespace Essensoft.AspNetCore.Payment.Alipay.Request
 {
     /// <summary>
-    /// AOP API: alipay.daowei.service.price.modify
+    /// AOP API: koubei.catering.commodity.order.buy
     /// </summary>
-    public class AlipayDaoweiServicePriceModifyRequest : IAlipayRequest<AlipayDaoweiServicePriceModifyResponse>
+    public class KoubeiCateringCommodityOrderBuyRequest : IAlipayRequest<KoubeiCateringCommodityOrderBuyResponse>
     {
         /// <summary>
-        /// 更新服务价格接口
+        /// isv订购口碑插件接口
         /// </summary>
         public string BizContent { get; set; }
 
@@ -74,7 +74,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Request
 
         public string GetApiName()
         {
-            return "alipay.daowei.service.price.modify";
+            return "koubei.catering.commodity.order.buy";
         }
 
         public void SetApiVersion(string apiVersion){

+ 0 - 9
src/Essensoft.AspNetCore.Payment.Alipay/Response/AlipayDaoweiServicePriceModifyResponse.cs

@@ -1,9 +0,0 @@
-namespace Essensoft.AspNetCore.Payment.Alipay.Response
-{
-    /// <summary>
-    /// AlipayDaoweiServicePriceModifyResponse.
-    /// </summary>
-    public class AlipayDaoweiServicePriceModifyResponse : AlipayResponse
-    {
-    }
-}

+ 0 - 6
src/Essensoft.AspNetCore.Payment.Alipay/Response/AlipayEcoEduKtBillingSendResponse.cs

@@ -12,11 +12,5 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Response
         /// </summary>
         [JsonProperty("order_no")]
         public string OrderNo { get; set; }
-
-        /// <summary>
-        /// 支付宝-中小学-教育缴费生成的学生唯一编号
-        /// </summary>
-        [JsonProperty("student_no")]
-        public string StudentNo { get; set; }
     }
 }

+ 12 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Response/AlipayTradeFastpayRefundQueryResponse.cs

@@ -7,6 +7,12 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Response
     /// </summary>
     public class AlipayTradeFastpayRefundQueryResponse : AlipayResponse
     {
+        /// <summary>
+        /// 退款失败错误码。只在使用异步退款接口情况下才会返回该字段
+        /// </summary>
+        [JsonProperty("error_code")]
+        public string ErrorCode { get; set; }
+
         /// <summary>
         /// 行业特殊信息(例如在医保卡支付退款中,医保局向商户返回医疗信息)。
         /// </summary>
@@ -55,6 +61,12 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Response
         [JsonProperty("refund_reason")]
         public string RefundReason { get; set; }
 
+        /// <summary>
+        /// 只在使用异步退款接口情况下才返回该字段。REFUND_PROCESSING 退款处理中;REFUND_SUCCESS 退款处理成功;REFUND_FAIL 退款失败;
+        /// </summary>
+        [JsonProperty("refund_status")]
+        public string RefundStatus { get; set; }
+
         /// <summary>
         /// 该笔退款所对应的交易的订单金额
         /// </summary>

+ 35 - 0
src/Essensoft.AspNetCore.Payment.Alipay/Response/KoubeiCateringCommodityOrderBuyResponse.cs

@@ -0,0 +1,35 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.Alipay.Response
+{
+    /// <summary>
+    /// KoubeiCateringCommodityOrderBuyResponse.
+    /// </summary>
+    public class KoubeiCateringCommodityOrderBuyResponse : AlipayResponse
+    {
+        /// <summary>
+        /// 扩展字段,供以后拓展使用
+        /// </summary>
+        [JsonProperty("ext_info")]
+        public List<string> ExtInfo { get; set; }
+
+        /// <summary>
+        /// order_result为success时返回;order_result为fail的时候不返回
+        /// </summary>
+        [JsonProperty("order_id")]
+        public string OrderId { get; set; }
+
+        /// <summary>
+        /// success表示订购成功;fail表示订购失败
+        /// </summary>
+        [JsonProperty("order_result")]
+        public string OrderResult { get; set; }
+
+        /// <summary>
+        /// 描述订购结果信息
+        /// </summary>
+        [JsonProperty("order_result_msg")]
+        public string OrderResultMsg { get; set; }
+    }
+}

+ 2 - 1
src/Essensoft.AspNetCore.Payment.Alipay/Utility/AlipayEncrypt.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Security.Cryptography;
 using System.Text;
+
 namespace Essensoft.AspNetCore.Payment.Alipay.Utility
 {
     internal class AlipayEncrypt
@@ -59,7 +60,7 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Utility
         }
 
         /// <summary>
-        ///     初始化向量
+        ///    初始化向量
         /// </summary>
         /// <param name="blockSize"></param>
         /// <returns></returns>

+ 2 - 9
src/Essensoft.AspNetCore.Payment.Alipay/Utility/AlipaySignature.cs

@@ -15,10 +15,9 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Utility
             if (para == null || para.Count == 0)
                 return string.Empty;
 
-            var sortedDic = new SortedDictionary<string, string>(para);
-
+            var sortPara = new SortedDictionary<string, string>(para);
             var sb = new StringBuilder();
-            foreach (var iter in sortedDic)
+            foreach (var iter in sortPara)
             {
                 if (!string.IsNullOrEmpty(iter.Value))
                     sb.Append(iter.Key).Append("=").Append(iter.Value).Append("&");
@@ -34,12 +33,6 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Utility
             return Convert.ToBase64String(rsa.SignData(Encoding.UTF8.GetBytes(data), "RSA2" == signType ? HashAlgorithmName.SHA256 : HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1));
         }
 
-        public static string RSASign(IDictionary<string, string> content, RSAParameters parameters, string signType)
-        {
-            var signContent = GetSignContent(content);
-            return RSASignContent(signContent, parameters, signType);
-        }
-
         public static bool RSACheckContent(string signContent, string sign, RSAParameters parameters, string signType)
         {
             try

+ 2 - 2
src/Essensoft.AspNetCore.Payment.Alipay/Utility/AlipayUtils.cs → src/Essensoft.AspNetCore.Payment.Alipay/Utility/AlipayUtility.cs

@@ -6,12 +6,12 @@ namespace Essensoft.AspNetCore.Payment.Alipay.Utility
     /// <summary>
     /// Alipay系统工具类。
     /// </summary>
-    public abstract class AlipayUtility
+    public static class AlipayUtility
     {
         /// <summary>m>
         /// <param name="bizContent"></param>
         /// <param name="charset"></param>
-        ///  AES加密
+        /// AES加密
         /// </summary>
         /// <param name="encryptKey"></para
         /// <returns></returns>

+ 4 - 3
src/Essensoft.AspNetCore.Payment.All/Essensoft.AspNetCore.Payment.All.csproj

@@ -2,7 +2,7 @@
 
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
-    <Version>1.2.1</Version>
+    <Version>1.3.0</Version>
     <Authors>Roc</Authors>
     <Company>Essensoft</Company>
     <Product>Payment</Product>
@@ -11,14 +11,15 @@
     <RepositoryType>git</RepositoryType>
     <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
     <Description>ASP.NET Core Payment</Description>
-    <AssemblyVersion>1.2.1.0</AssemblyVersion>
-    <FileVersion>1.2.1.0</FileVersion>
+    <AssemblyVersion>1.3.0.0</AssemblyVersion>
+    <FileVersion>1.3.0.0</FileVersion>
     <PackageProjectUrl>https://github.com/Essensoft/Payment</PackageProjectUrl>
   </PropertyGroup>
 
   <ItemGroup>
     <ProjectReference Include="..\Essensoft.AspNetCore.Payment.Alipay\Essensoft.AspNetCore.Payment.Alipay.csproj" />
     <ProjectReference Include="..\Essensoft.AspNetCore.Payment.JdPay\Essensoft.AspNetCore.Payment.JdPay.csproj" />
+    <ProjectReference Include="..\Essensoft.AspNetCore.Payment.LianLianPay\Essensoft.AspNetCore.Payment.LianLianPay.csproj" />
     <ProjectReference Include="..\Essensoft.AspNetCore.Payment.QPay\Essensoft.AspNetCore.Payment.QPay.csproj" />
     <ProjectReference Include="..\Essensoft.AspNetCore.Payment.UnionPay\Essensoft.AspNetCore.Payment.UnionPay.csproj" />
     <ProjectReference Include="..\Essensoft.AspNetCore.Payment.WeChatPay\Essensoft.AspNetCore.Payment.WeChatPay.csproj" />

+ 0 - 1
src/Essensoft.AspNetCore.Payment.JdPay/Domain/PayTradeVo.cs

@@ -2,7 +2,6 @@
 
 namespace Essensoft.AspNetCore.Payment.JdPay.Domain
 {
-    [XmlRoot("pay")]
     public class PayTradeVo
     {
         /// <summary>

+ 3 - 3
src/Essensoft.AspNetCore.Payment.JdPay/Essensoft.AspNetCore.Payment.JdPay.csproj

@@ -5,9 +5,9 @@
     <Company>Essensoft</Company>
     <Authors>Roc</Authors>
     <Product>Payment</Product>
-    <Version>1.2.1</Version>
-    <AssemblyVersion>1.2.1.0</AssemblyVersion>
-    <FileVersion>1.2.1.0</FileVersion>
+    <Version>1.3.0</Version>
+    <AssemblyVersion>1.3.0.0</AssemblyVersion>
+    <FileVersion>1.3.0.0</FileVersion>
     <Description>ASP.NET Core Payment for JdPay.</Description>
     <Copyright>© Essensoft 2018</Copyright>
     <PackageProjectUrl>https://github.com/Essensoft/Payment</PackageProjectUrl>

+ 77 - 62
src/Essensoft.AspNetCore.Payment.JdPay/JdPayClient.cs

@@ -1,4 +1,5 @@
-using Essensoft.AspNetCore.Payment.JdPay.Utility;
+using Essensoft.AspNetCore.Payment.JdPay.Parser;
+using Essensoft.AspNetCore.Payment.JdPay.Utility;
 using Essensoft.AspNetCore.Security;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Options;
@@ -73,31 +74,89 @@ namespace Essensoft.AspNetCore.Payment.JdPay
             // 字典排序
             var sortedTxtParams = new JdPayDictionary(request.GetParameters());
 
-            var content = GetEncryptXmlContent(request, sortedTxtParams);
-            Logger.LogInformation(0, "Request Content:{content}", content);
+            var content = BuildEncryptXml(request, sortedTxtParams);
+            Logger.LogInformation(0, "Request:{content}", content);
 
             var rspContent = await Client.DoPostAsync(request.GetRequestUrl(), content);
-            Logger.LogInformation(1, "Response Content:{content}", rspContent);
+            Logger.LogInformation(1, "Response:{content}", rspContent);
 
-            var formatStr = JdPayUtil.FotmatXmlString(rspContent);
-            return DecryptResponseXmlContent<T>(formatStr);
+            var parser = new JdPayXmlParser<T>();
+            var rsp = parser.Parse(JdPayUtility.FotmatXmlString(rspContent));
+            if (!string.IsNullOrEmpty(rsp.Encrypt))
+            {
+                var encrypt = rsp.Encrypt;
+                var base64EncryptStr = Encoding.UTF8.GetString(Convert.FromBase64String(encrypt));
+                var reqBody = DES3.DecryptECB(DesKey, base64EncryptStr);
+                Logger.LogInformation(2, "Encrypt Content:{body}", reqBody);
+
+                var reqBodyDoc = new XmlDocument();
+                reqBodyDoc.LoadXml(reqBody);
+
+                var sign = JdPayUtility.GetValue(reqBodyDoc, "sign");
+                var rootNode = reqBodyDoc.SelectSingleNode("jdpay");
+                var signNode = rootNode.SelectSingleNode("sign");
+                rootNode.RemoveChild(signNode);
+
+                var reqBodyStr = JdPayUtility.ConvertXmlToString(reqBodyDoc);
+                var xmlh = rsp.Body.Substring(0, rsp.Body.IndexOf("<jdpay>"));
+                if (!string.IsNullOrEmpty(xmlh))
+                {
+                    reqBodyStr = reqBodyStr.Replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", xmlh);
+                }
+                var sha256SourceSignString = SHA256.Compute(reqBodyStr);
+                var decryptByte = JdPaySignature.Decrypt(sign, RSAPublicParameters);
+                var decryptStr = DES3.BytesToString(decryptByte);
+                if (sha256SourceSignString == decryptStr)
+                {
+                    rsp = parser.Parse(reqBody);
+                    rsp.Encrypt = encrypt;
+                }
+                else
+                {
+                    throw new Exception("sign check fail: check Sign and Data Fail!");
+                }
+            }
+            return rsp;
         }
 
         public Task<T> PageExecuteAsync<T>(IJdPayRequest<T> request, string reqMethod) where T : JdPayResponse
         {
             // 字典排序
             var sortedTxtParams = new JdPayDictionary(request.GetParameters());
-            var encyptParams = GetEncryptDicContent(request, sortedTxtParams);
+            var encyptParams = BuildEncryptDic(request, sortedTxtParams);
             var rsp = Activator.CreateInstance<T>();
-            rsp.Body = GetHtmlRequestContent(request.GetRequestUrl(), encyptParams, reqMethod);
-            Logger.LogInformation(0, "Request Html:{body}", rsp.Body);
+
+            var url = request.GetRequestUrl();
+            if (reqMethod == "GET")
+            {
+                //拼接get请求的url
+                var tmpUrl = url;
+                if (encyptParams != null && encyptParams.Count > 0)
+                {
+                    if (tmpUrl.Contains("?"))
+                    {
+                        tmpUrl = tmpUrl + "&" + HttpClientEx.BuildQuery(encyptParams);
+                    }
+                    else
+                    {
+                        tmpUrl = tmpUrl + "?" + HttpClientEx.BuildQuery(encyptParams);
+                    }
+                }
+                rsp.Body = tmpUrl;
+            }
+            else
+            {
+                //输出post表单
+                rsp.Body = BuildHtmlRequest(url, encyptParams);
+            }
+
             return Task.FromResult(rsp);
         }
 
-        private string GetEncryptXmlContent<T>(IJdPayRequest<T> request, JdPayDictionary dic) where T : JdPayResponse
+        private string BuildEncryptXml<T>(IJdPayRequest<T> request, JdPayDictionary dic) where T : JdPayResponse
         {
-            var xmldoc = JdPayUtil.SortedDictionary2AllXml(dic);
-            var smlStr = JdPayUtil.ConvertXmlToString(xmldoc);
+            var xmldoc = JdPayUtility.SortedDictionary2AllXml(dic);
+            var smlStr = JdPayUtility.ConvertXmlToString(xmldoc);
             var sha256SourceSignString = SHA256.Compute(smlStr);
             var encyptBytes = JdPaySignature.Encrypt(sha256SourceSignString, RSAPrivateParameters);
             var sign = Convert.ToBase64String(encyptBytes, Base64FormattingOptions.InsertLineBreaks);
@@ -111,10 +170,10 @@ namespace Essensoft.AspNetCore.Payment.JdPay
                 { ENCRYPT, Convert.ToBase64String(Encoding.UTF8.GetBytes(encrypt)) }
             };
 
-            return JdPayUtil.SortedDictionary2XmlStr(reqdic);
+            return JdPayUtility.SortedDictionary2XmlStr(reqdic);
         }
 
-        private JdPayDictionary GetEncryptDicContent<T>(IJdPayRequest<T> request, IDictionary<string, string> dic) where T : JdPayResponse
+        private JdPayDictionary BuildEncryptDic<T>(IJdPayRequest<T> request, IDictionary<string, string> dic) where T : JdPayResponse
         {
             var signDic = new JdPayDictionary(dic)
             {
@@ -122,7 +181,8 @@ namespace Essensoft.AspNetCore.Payment.JdPay
                 { MERCHANT, Options.Merchant },
             };
 
-            var sign = JdPaySignature.RSASign(signDic, RSAPrivateParameters);
+            var signContent = JdPaySignature.GetSignContent(signDic);
+            var sign = JdPaySignature.RSASign(signContent, RSAPrivateParameters);
 
             var encyptDic = new JdPayDictionary
             {
@@ -141,55 +201,10 @@ namespace Essensoft.AspNetCore.Payment.JdPay
             return encyptDic;
         }
 
-        private T DecryptResponseXmlContent<T>(string xml) where T : JdPayResponse
-        {
-            if (string.IsNullOrEmpty(xml))
-            {
-                throw new Exception("Content is Empty!");
-            }
-
-            var entity = JdPayUtil.Deserialize<T>(xml);
-            if (!string.IsNullOrEmpty(entity?.Encrypt))
-            {
-                var base64EncryptStr = Encoding.UTF8.GetString(Convert.FromBase64String(entity.Encrypt));
-                var reqBody = DES3.DecryptECB(DesKey, base64EncryptStr);
-
-                var reqBodyDoc = new XmlDocument();
-                reqBodyDoc.LoadXml(reqBody);
-
-                var inputSign = JdPayUtil.GetValue(reqBodyDoc, "sign");
-                var jdpayRoot = reqBodyDoc.SelectSingleNode("jdpay");
-                var signNode = jdpayRoot.SelectSingleNode("sign");
-                jdpayRoot.RemoveChild(signNode);
-
-                var reqBodyStr = JdPayUtil.ConvertXmlToString(reqBodyDoc);
-                var xmlh = xml.Substring(0, xml.IndexOf("<jdpay>"));
-                if (!string.IsNullOrEmpty(xmlh))
-                {
-                    reqBodyStr = reqBodyStr.Replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", xmlh);
-                }
-                if (JdPaySignature.RSACheckContent(reqBodyStr, inputSign, RSAPublicParameters))
-                {
-                    entity = JdPayUtil.Deserialize<T>(reqBody);
-                }
-                else
-                {
-                    throw new Exception("sign check fail: check Sign and Data Fail!");
-                }
-
-                entity.Body = reqBody;
-            }
-            else
-            {
-                entity.Body = xml;
-            }
-            return entity;
-        }
-
-        private string GetHtmlRequestContent(string url, JdPayDictionary dicPara, string strMethod)
+        private string BuildHtmlRequest(string url, JdPayDictionary dicPara)
         {
             var sbHtml = new StringBuilder();
-            sbHtml.Append("<form id='submit' name='submit' action='" + url + "' method='" + strMethod + "' style='display:none;'>");
+            sbHtml.Append("<form id='submit' name='submit' action='" + url + "' method='post' style='display:none;'>");
             foreach (var temp in dicPara)
             {
                 sbHtml.Append("<input  name='" + temp.Key + "' value='" + temp.Value + "'/>");

+ 62 - 62
src/Essensoft.AspNetCore.Payment.JdPay/JdPayNotifyClient.cs

@@ -57,100 +57,100 @@ namespace Essensoft.AspNetCore.Payment.JdPay
 
         public async Task<T> ExecuteAsync<T>(HttpRequest request) where T : JdPayNotifyResponse
         {
-            if (request.ContentType == "application/x-www-form-urlencoded")
+            if (request.HasFormContentType)
             {
-                var dic = new JdPayDictionary();
-                foreach (var item in request.Form)
-                {
-                    if (!string.IsNullOrEmpty(item.Value))
-                    {
-                        if (item.Key == "sign")
-                        {
-                            dic.Add(item.Key, item.Value);
-                        }
-                        else
-                        {
-                            dic.Add(item.Key, DES3.DecryptECB(DesKey, item.Value));
-                        }
-                    }
-                }
+                var parameters = await GetParametersAsync(request);
 
-                var query = HttpClientEx.BuildQuery(dic);
-                Logger.LogInformation(1, "Request Content:{query}", query);
+                var query = HttpClientEx.BuildQuery(parameters);
+                Logger.LogInformation(0, "Request:{query}", query);
 
                 var parser = new JdPayDictionaryParser<T>();
-                var rsp = parser.Parse(dic);
+                var rsp = parser.Parse(parameters);
 
-                CheckNotifySign(dic, RSAPrivateParameters);
+                CheckNotifySign(rsp.Parameters, RSAPrivateParameters);
                 return rsp;
             }
-            else
+            else if(request.HasTextXmlContentType())
             {
                 var body = await new StreamReader(request.Body).ReadToEndAsync();
-                Logger.LogInformation(1, "Request Content:{body}", body);
+                Logger.LogInformation(0, "Request:{body}", body);
 
-                var rsp = DecryptResponseXml<T>(JdPayUtil.FotmatXmlString(body));
+                var parser = new JdPayXmlParser<T>();
+                var rsp = parser.Parse(JdPayUtility.FotmatXmlString(body));
+                if (!string.IsNullOrEmpty(rsp.Encrypt))
+                {
+                    var encrypt = rsp.Encrypt;
+                    var base64EncryptStr = Encoding.UTF8.GetString(Convert.FromBase64String(encrypt));
+                    var reqBody = DES3.DecryptECB(DesKey, base64EncryptStr);
+                    Logger.LogInformation(1, "Encrypt Content:{body}", reqBody);
+
+                    var reqBodyDoc = new XmlDocument();
+                    reqBodyDoc.LoadXml(reqBody);
+
+                    var sign = JdPayUtility.GetValue(reqBodyDoc, "sign");
+                    var rootNode = reqBodyDoc.SelectSingleNode("jdpay");
+                    var signNode = rootNode.SelectSingleNode("sign");
+                    rootNode.RemoveChild(signNode);
+
+                    var reqBodyStr = JdPayUtility.ConvertXmlToString(reqBodyDoc);
+                    var xmlh = rsp.Body.Substring(0, rsp.Body.IndexOf("<jdpay>"));
+                    if (!string.IsNullOrEmpty(xmlh))
+                    {
+                        reqBodyStr = reqBodyStr.Replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", xmlh);
+                    }
+                    var sha256SourceSignString = SHA256.Compute(reqBodyStr);
+                    var decryptByte = JdPaySignature.Decrypt(sign, RSAPublicParameters);
+                    var decryptStr = DES3.BytesToString(decryptByte);
+                    if (sha256SourceSignString == decryptStr)
+                    {
+                        rsp = parser.Parse(reqBody);
+                        rsp.Encrypt = encrypt;
+                    }
+                    else
+                    {
+                        throw new Exception("sign check fail: check Sign and Data Fail!");
+                    }
+                }
                 return rsp;
             }
+            else
+            {
+                throw new Exception("sign check fail: check Sign and Data Fail!");
+            }
         }
 
-        private T DecryptResponseXml<T>(string xml) where T : JdPayNotifyResponse
+        private async Task<JdPayDictionary> GetParametersAsync(HttpRequest request)
         {
-            var entity = JdPayUtil.Deserialize<T>(xml);
-            if (!string.IsNullOrEmpty(entity?.Encrypt))
+            var parameters = new JdPayDictionary();
+            var form = await request.ReadFormAsync();
+            foreach (var item in form)
             {
-                var base64EncryptStr = Encoding.UTF8.GetString(Convert.FromBase64String(entity.Encrypt));
-                var reqBody = DES3.DecryptECB(DesKey, base64EncryptStr);
-
-                var reqBodyDoc = new XmlDocument();
-                reqBodyDoc.LoadXml(reqBody);
-
-                var inputSign = JdPayUtil.GetValue(reqBodyDoc, "sign");
-                var jdpayRoot = reqBodyDoc.SelectSingleNode("jdpay");
-                var signNode = jdpayRoot.SelectSingleNode("sign");
-                jdpayRoot.RemoveChild(signNode);
-
-                var reqBodyStr = JdPayUtil.ConvertXmlToString(reqBodyDoc);
-                var xmlh = xml.Substring(0, xml.IndexOf("<jdpay>"));
-                if (!string.IsNullOrEmpty(xmlh))
+                if (item.Key != "sign")
                 {
-                    reqBodyStr = reqBodyStr.Replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", xmlh);
-                }
-                var sha256SourceSignString = SHA256.Compute(reqBodyStr);
-                var decryptByte = JdPaySignature.Decrypt(inputSign, RSAPublicParameters);
-                var decryptStr = DES3.BytesToString(decryptByte);
-                if (sha256SourceSignString == decryptStr)
-                {
-                    entity = JdPayUtil.Deserialize<T>(reqBody);
+                    parameters.Add(item.Key, DES3.DecryptECB(DesKey, item.Value));
                 }
                 else
                 {
-                    throw new Exception("sign check fail: check Sign and Data Fail!");
+                    parameters.Add(item.Key, item.Value);
                 }
-
-                entity.Body = reqBody;
-            }
-            else
-            {
-                entity.Body = xml;
             }
-            return entity;
+            return parameters;
         }
 
-        private void CheckNotifySign(JdPayDictionary content, object parameters)
+        private void CheckNotifySign(JdPayDictionary para, object parameters)
         {
-            if (content.Count == 0)
+            if (para.Count == 0)
             {
-                throw new Exception("sign check fail: Body is Empty!");
+                throw new Exception("sign check fail: para is Empty!");
             }
 
-            var sign = content["sign"];
-            if (string.IsNullOrEmpty(sign))
+            if (!para.TryGetValue("sign", out var sign))
             {
                 throw new Exception("sign check fail: sign is Empty!");
             }
 
-            if (!JdPaySignature.RSACheckContent(content, sign, RSAPublicParameters))
+            var signContent = JdPaySignature.GetSignContent(para);
+            if (!JdPaySignature.RSACheckContent(signContent, sign, RSAPublicParameters))
             {
                 throw new Exception("sign check fail: check Sign and Data Fail");
             }

+ 2 - 46
src/Essensoft.AspNetCore.Payment.JdPay/JdPayNotifyResponse.cs

@@ -1,50 +1,6 @@
-using Essensoft.AspNetCore.Payment.JdPay.Domain;
-using System.Xml.Serialization;
-
-namespace Essensoft.AspNetCore.Payment.JdPay
+namespace Essensoft.AspNetCore.Payment.JdPay
 {
-    public abstract class JdPayNotifyResponse : JdPayObject
+    public abstract class JdPayNotifyResponse : JdPayResponse
     {
-        /// <summary>
-        /// 版本号
-        /// </summary>
-        [XmlElement("version")]
-        public string Version { get; set; }
-
-        /// <summary>
-        /// 商户号
-        /// </summary>
-        [XmlElement("merchant")]
-        public string Merchant { get; set; }
-
-        /// <summary>
-        /// 门店号
-        /// </summary>
-        [XmlElement("device")]
-        public string Device { get; set; }
-
-        /// <summary>
-        /// 返回信息
-        /// </summary>
-        [XmlElement("result")]
-        public Result Result { get; set; }
-
-        /// <summary>
-        /// 数据签名
-        /// </summary>
-        [XmlElement("sign")]
-        public string Sign { get; set; }
-
-        /// <summary>
-        /// 加密报文
-        /// </summary>
-        [XmlElement("encrypt")]
-        public string Encrypt { get; set; }
-
-        /// <summary>
-        /// 完整报文
-        /// </summary>
-        [XmlIgnore]
-        public string Body { get; set; }
     }
 }

+ 12 - 6
src/Essensoft.AspNetCore.Payment.JdPay/JdPayResponse.cs

@@ -5,6 +5,18 @@ namespace Essensoft.AspNetCore.Payment.JdPay
 {
     public abstract class JdPayResponse : JdPayObject
     {
+        /// <summary>
+        /// 原始内容
+        /// </summary>
+        [XmlIgnore]
+        public string Body { get; set; }
+
+        /// <summary>
+        /// 原始参数
+        /// </summary>
+        [XmlIgnore]
+        public JdPayDictionary Parameters { get; internal set; }
+
         /// <summary>
         /// 版本号
         /// </summary>
@@ -40,11 +52,5 @@ namespace Essensoft.AspNetCore.Payment.JdPay
         /// </summary>
         [XmlElement("encrypt")]
         public string Encrypt { get; set; }
-
-        /// <summary>
-        /// 完整报文
-        /// </summary>
-        [XmlIgnore]
-        public string Body { get; set; }
     }
 }

+ 2 - 1
src/Essensoft.AspNetCore.Payment.JdPay/Notify/JdPayAsyncNotifyResponse.cs

@@ -25,7 +25,8 @@ namespace Essensoft.AspNetCore.Payment.JdPay.Notify
         /// <summary>
         /// 交易列表
         /// </summary>
-        [XmlElement("payList")]
+        [XmlArray("payList")]
+        [XmlArrayItem("pay")]
         public List<PayTradeVo> PayList { get; set; }
 
         // 退款相关字段

+ 2 - 2
src/Essensoft.AspNetCore.Payment.JdPay/Parser/IJdPayParser.cs

@@ -3,8 +3,8 @@
     /// <summary>
     /// 京东支付结果解析
     /// </summary>
-    public interface IJdPayParser<T> where T : JdPayObject
+    public interface IJdPayParser<T> where T : JdPayResponse
     {
-        T Parse(JdPayDictionary dic);
+        T Parse(string body);
     }
 }

+ 10 - 4
src/Essensoft.AspNetCore.Payment.JdPay/Parser/JdPayDictionaryParser.cs

@@ -7,7 +7,7 @@ using System.Xml.Serialization;
 
 namespace Essensoft.AspNetCore.Payment.JdPay.Parser
 {
-    public class JdPayDictionaryParser<T> : IJdPayParser<T> where T : JdPayObject
+    public class JdPayDictionaryParser<T> where T : JdPayResponse
     {
         private static readonly Dictionary<Type, Dictionary<string, PropertyInfo>> DicProperties = new Dictionary<Type, Dictionary<string, PropertyInfo>>();
 
@@ -20,14 +20,20 @@ namespace Essensoft.AspNetCore.Payment.JdPay.Parser
 
             var propertiesMap = DicProperties[typeof(T)];
 
-            var result = Activator.CreateInstance<T>();
+            var rsp = Activator.CreateInstance<T>();
 
             foreach (var item in dic)
             {
                 if (propertiesMap.ContainsKey(item.Key))
-                    propertiesMap[item.Key].SetValue(result, item.Value.TryTo(propertiesMap[item.Key].PropertyType));
+                    propertiesMap[item.Key].SetValue(rsp, item.Value.TryTo(propertiesMap[item.Key].PropertyType));
             }
-            return result;
+
+            if (rsp != null)
+            {
+                rsp.Parameters = dic;
+            }
+
+            return rsp;
         }
 
         private Dictionary<string, PropertyInfo> GetPropertiesMap(Type type)

+ 33 - 0
src/Essensoft.AspNetCore.Payment.JdPay/Parser/JdPayXmlParser.cs

@@ -0,0 +1,33 @@
+using System;
+using System.IO;
+using System.Xml.Serialization;
+
+namespace Essensoft.AspNetCore.Payment.JdPay.Parser
+{
+    public class JdPayXmlParser<T> : IJdPayParser<T> where T : JdPayResponse
+    {
+        public T Parse(string body)
+        {
+            T rsp = null;
+
+            try
+            {
+                using (var sr = new StringReader(body))
+                {
+                    var xmldes = new XmlSerializer(typeof(T));
+                    rsp = (T)xmldes.Deserialize(sr);
+                }
+            }
+            catch
+            { }
+
+            if (rsp == null)
+                rsp = Activator.CreateInstance<T>();
+
+            if (rsp != null)
+                rsp.Body = body;
+
+            return rsp;
+        }
+    }
+}

+ 2 - 1
src/Essensoft.AspNetCore.Payment.JdPay/Response/JdPayOrderQueryResponse.cs

@@ -40,7 +40,8 @@ namespace Essensoft.AspNetCore.Payment.JdPay.Response
         /// <summary>
         /// 交易列表
         /// </summary>
-        [XmlElement("payList")]
+        [XmlArray("payList")]
+        [XmlArrayItem("pay")]
         public List<PayTradeVo> PayList { get; set; }
     }
 }

+ 2 - 10
src/Essensoft.AspNetCore.Payment.JdPay/Utility/JdPaySignature.cs

@@ -4,14 +4,13 @@ using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Security;
 using System;
-using System.Collections.Generic;
 using System.Text;
 
 namespace Essensoft.AspNetCore.Payment.JdPay.Utility
 {
     public class JdPaySignature
     {
-        public static string GetSignContent(SortedDictionary<string, string> para)
+        public static string GetSignContent(JdPayDictionary para)
         {
             if (para == null || para.Count == 0)
                 return string.Empty;
@@ -26,20 +25,13 @@ namespace Essensoft.AspNetCore.Payment.JdPay.Utility
             return sb.Remove(sb.Length - 1, 1).ToString();
         }
 
-        public static string RSASign(SortedDictionary<string, string> dic, ICipherParameters parameters)
+        public static string RSASign(string sourceSignString, ICipherParameters parameters)
         {
-            var sourceSignString = GetSignContent(dic);
             var sha256SourceSignString = SHA256.Compute(sourceSignString);
             var newsks = Encrypt(sha256SourceSignString, parameters);
             return Convert.ToBase64String(newsks, Base64FormattingOptions.InsertLineBreaks);
         }
 
-        public static bool RSACheckContent(SortedDictionary<string, string> dic, string sign, ICipherParameters parameters)
-        {
-            var strSourceData = GetSignContent(dic);
-            return RSACheckContent(strSourceData, sign, parameters);
-        }
-
         public static bool RSACheckContent(string content, string sign, ICipherParameters parameters)
         {
             var sha256SourceSignString = SHA256.Compute(content);

+ 55 - 11
src/Essensoft.AspNetCore.Payment.JdPay/Utility/JdPayUtil.cs → src/Essensoft.AspNetCore.Payment.JdPay/Utility/JdPayUtility.cs

@@ -1,28 +1,72 @@
-using System;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.ComponentModel;
 using System.IO;
+using System.Linq.Expressions;
+using System.Net.Http.Headers;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Xml;
-using System.Xml.Serialization;
 
 namespace Essensoft.AspNetCore.Payment.JdPay.Utility
 {
-    public class JdPayUtil
+    public static class JdPayUtility
     {
-        public static T Deserialize<T>(string xml)
+        internal static bool HasTextXmlContentType(this HttpRequest request)
+        {
+            // Content-Type: text/xml
+            MediaTypeHeaderValue.TryParse(request.ContentType, out var contentType);
+            return contentType != null && contentType.MediaType.Equals("text/xml", StringComparison.OrdinalIgnoreCase);
+        }
+
+        internal static object TryTo<T>(this object Object)
+        {
+            return Object.TryTo(typeof(T));
+        }
+
+        /// <summary>
+        /// 尝试将对象实例转换成目标类型
+        /// </summary>
+        /// <typeparam name="T">对象实例类型</typeparam>
+        /// <typeparam name="R">目标类型</typeparam>
+        /// <param name="Object">对象实例</param>
+        /// <param name="DefaultValue">默认值</param>
+        /// <returns>转换后类型</returns>
+        internal static object TryTo(this object Object, Type destinationType)
         {
             try
             {
-                using (var sr = new StringReader(xml))
+                if (Object == null || Convert.IsDBNull(Object))
+                    return GetDefault(destinationType);
+                if ((Object as string) != null)
                 {
-                    var xmldes = new XmlSerializer(typeof(T));
-                    return (T)xmldes.Deserialize(sr);
+                    var ObjectValue = Object as string;
+                    if (destinationType.IsEnum)
+                        return System.Enum.Parse(destinationType, ObjectValue, true);
+                    if (string.IsNullOrEmpty(ObjectValue))
+                        return GetDefault(destinationType);
                 }
+                if ((Object as IConvertible) != null)
+                {
+                    var destination =
+                       destinationType.IsGenericType && destinationType.GetGenericTypeDefinition() == typeof(Nullable<>) ?
+                           Nullable.GetUnderlyingType(destinationType) : destinationType;
+                    return Convert.ChangeType(Object, destination);
+                }
+                if (destinationType.IsAssignableFrom(Object.GetType()))
+                    return Object;
+                var Converter = TypeDescriptor.GetConverter(Object.GetType());
+                if (Converter.CanConvertTo(destinationType))
+                    return Converter.ConvertTo(Object, destinationType);
             }
-            catch (Exception e)
-            {
-                throw new Exception(e.Message);
-            }
+            catch { }
+            return GetDefault(destinationType);
+        }
+
+        private static object GetDefault(Type type)
+        {
+            var defaultExpr = Expression.Default(type);
+            return Expression.Lambda<Func<object>>(defaultExpr).Compile()();
         }
 
         public static string GetValue(XmlDocument doc, string name)

+ 0 - 59
src/Essensoft.AspNetCore.Payment.JdPay/Utility/Utility.cs

@@ -1,59 +0,0 @@
-using System;
-using System.ComponentModel;
-using System.Linq.Expressions;
-
-namespace Essensoft.AspNetCore.Payment.JdPay.Utility
-{
-    public static class Utility
-    {
-        internal static object TryTo<T>(this object Object)
-        {
-            return Object.TryTo(typeof(T));
-        }
-
-        /// <summary>
-        /// 尝试将对象实例转换成目标类型
-        /// </summary>
-        /// <typeparam name="T">对象实例类型</typeparam>
-        /// <typeparam name="R">目标类型</typeparam>
-        /// <param name="Object">对象实例</param>
-        /// <param name="DefaultValue">默认值</param>
-        /// <returns>转换后类型</returns>
-        internal static object TryTo(this object Object, Type destinationType)
-        {
-            try
-            {
-                if (Object == null || Convert.IsDBNull(Object))
-                    return GetDefault(destinationType);
-                if ((Object as string) != null)
-                {
-                    var ObjectValue = Object as string;
-                    if (destinationType.IsEnum)
-                        return System.Enum.Parse(destinationType, ObjectValue, true);
-                    if (string.IsNullOrEmpty(ObjectValue))
-                        return GetDefault(destinationType);
-                }
-                if ((Object as IConvertible) != null)
-                {
-                    var destination =
-                       destinationType.IsGenericType && destinationType.GetGenericTypeDefinition() == typeof(Nullable<>) ?
-                           Nullable.GetUnderlyingType(destinationType) : destinationType;
-                    return Convert.ChangeType(Object, destination);
-                }
-                if (destinationType.IsAssignableFrom(Object.GetType()))
-                    return Object;
-                var Converter = TypeDescriptor.GetConverter(Object.GetType());
-                if (Converter.CanConvertTo(destinationType))
-                    return Converter.ConvertTo(Object, destinationType);
-            }
-            catch { }
-            return GetDefault(destinationType);
-        }
-
-        private static object GetDefault(Type type)
-        {
-            var defaultExpr = Expression.Default(type);
-            return Expression.Lambda<Func<object>>(defaultExpr).Compile()();
-        }
-    }
-}

+ 46 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/Domain/Agreement.cs

@@ -0,0 +1,46 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay.Domain
+{
+    public class Agreement
+    {
+        /// <summary>
+        /// 签约协议号
+        /// 银行卡签约的唯一编号
+        /// </summary>
+        [JsonProperty("no_agree")]
+        public string NoAgree { get; set; }
+
+        /// <summary>
+        /// 银行卡号后4位
+        /// </summary>
+        [JsonProperty("card_no")]
+        public string CardNo { get; set; }
+
+        /// <summary>
+        /// 所属银行编号
+        /// </summary>
+        [JsonProperty("bank_code")]
+        public string BankCode { get; set; }
+
+        /// <summary>
+        /// 所属银行名称
+        /// </summary>
+        [JsonProperty("bank_name")]
+        public string BankName { get; set; }
+
+        /// <summary>
+        /// 银行卡类型
+        /// 2-储蓄卡  3-信用卡 
+        /// </summary>
+        [JsonProperty("card_type")]
+        public string CardType { get; set; }
+
+        /// <summary>
+        /// 绑定手机号码
+        /// 手机号码
+        /// </summary>
+        [JsonProperty("bind_mobile")]
+        public string BindMobile { get; set; }
+    }
+}

+ 58 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/Domain/SupportBank.cs

@@ -0,0 +1,58 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay.Domain
+{
+    public class SupportBank
+    {
+        /// <summary>
+        /// 银行编号
+        /// </summary>
+        [JsonProperty("bank_code")]
+        public string BankCode { get; set; }
+
+        /// <summary>
+        /// 银行名称
+        /// </summary>
+        [JsonProperty("bank_name")]
+        public string BankName { get; set; }
+
+        /// <summary>
+        /// 银行卡类型
+        /// 2-储蓄卡  3-信用卡 
+        /// </summary>
+        [JsonProperty("card_type")]
+        public string CardType { get; set; }
+
+        /// <summary>
+        /// 单笔限额
+        /// 单位 元 整数数字
+        /// 最大限额 90000000,需商户前端自行处理
+        /// </summary>
+        [JsonProperty("single_amt")]
+        public string SingleAmt { get; set; }
+
+        /// <summary>
+        /// 单日限额
+        /// 单位 元 整数数字 
+        /// 最大限额 90000000,需商户前端自行处理
+        /// </summary>
+        [JsonProperty("day_amt")]
+        public string DayAmt { get; set; }
+
+        /// <summary>
+        /// 单月限额
+        /// 单位 元 整数数字 
+        /// 最大限额 90000000,需商户前端自行处理
+        /// </summary>
+        [JsonProperty("month_amt")]
+        public string MonthAmt { get; set; }
+
+        /// <summary>
+        /// 银行状态
+        /// 0:正常
+        /// 2:维护中
+        /// </summary>
+        [JsonProperty("bank_status")]
+        public string BankStatus { get; set; }
+    }
+}

+ 28 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/Essensoft.AspNetCore.Payment.LianLianPay.csproj

@@ -0,0 +1,28 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
+    <Version>1.3.0</Version>
+    <Product>Payment</Product>
+    <Copyright>© Essensoft 2018</Copyright>
+    <PackageProjectUrl>https://github.com/Essensoft/Payment</PackageProjectUrl>
+    <RepositoryUrl>https://github.com/Essensoft/Payment</RepositoryUrl>
+    <RepositoryType>git</RepositoryType>
+    <Description>ASP.NET Core Payment for LianLianPay.</Description>
+    <Company>Essensoft</Company>
+    <Authors>Roc</Authors>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.0.2" />
+    <PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.1" />
+    <PackageReference Include="Microsoft.Extensions.Options" Version="2.0.1" />
+    <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Essensoft.AspNetCore.Payment.Security\Essensoft.AspNetCore.Payment.Security.csproj" />
+  </ItemGroup>
+
+</Project>

+ 22 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/ILianLianPayClient.cs

@@ -0,0 +1,22 @@
+using System.Threading.Tasks;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay
+{
+    public interface ILianLianPayClient
+    {
+        /// <summary>
+        /// 执行LianLianPay API请求。
+        /// </summary>
+        /// <param name="request">具体的JdPay API请求</param>
+        /// <returns>领域对象</returns>
+        Task<T> ExecuteAsync<T>(ILianLianPayRequest<T> request) where T : LianLianPayResponse;
+
+        /// <summary>
+        /// 执行LianLianPay API请求。
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="request">具体的LianLianPay API请求</param>
+        /// <returns></returns>
+        Task<T> PageExecuteAsync<T>(ILianLianPayRequest<T> request, string reqMethod) where T : LianLianPayResponse;
+    }
+}

+ 33 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/ILianLianPayRequest.cs

@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay
+{
+    public interface ILianLianPayRequest<T> where T : LianLianPayResponse
+    {
+        /// <summary>
+        /// API接口地址
+        /// </summary>
+        /// <returns></returns>
+        string GetRequestUrl();
+
+        /// <summary>
+        /// 获取API版本
+        /// </summary>
+        /// <returns></returns>
+        string GetApiVersion();
+
+        /// <summary>
+        /// 设置API版本
+        /// </summary>
+        /// <param name="apiVersion"></param>
+        void SetApiVersion(string apiVersion);
+
+        /// <summary>
+        /// 获取所有的Key-Value形式的文本请求参数字典。其中:
+        /// Key: 请求参数名
+        /// Value: 请求参数文本值
+        /// </summary>
+        /// <returns>文本请求参数字典</returns>
+        IDictionary<string, string> GetParameters();
+    }
+}

+ 192 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/LianLianPayClient.cs

@@ -0,0 +1,192 @@
+using Essensoft.AspNetCore.Payment.LianLianPay.Parser;
+using Essensoft.AspNetCore.Payment.LianLianPay.Request;
+using Essensoft.AspNetCore.Payment.LianLianPay.Utility;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay
+{
+    public class LianLianPayClient : ILianLianPayClient
+    {
+        private const string VERSION = "version";
+        private const string OID_PARTNER = "oid_partner";
+        private const string SIGN_TYPE = "sign_type";
+        private const string BUSI_PARTNER = "busi_partner";
+        private const string TIMESTAMP = "timestamp";
+        private const string SIGN = "sign";
+
+        private RSAParameters RSAPrivateParameters;
+        private RSAParameters RSAPublicParameters;
+
+        public LianLianPayOptions Options { get; set; }
+
+        public virtual ILogger<LianLianPayClient> Logger { get; set; }
+
+        protected internal HttpClientEx Client { get; set; }
+
+        public LianLianPayClient(
+            IOptions<LianLianPayOptions> optionsAccessor,
+            ILogger<LianLianPayClient> logger)
+        {
+            Options = optionsAccessor?.Value ?? new LianLianPayOptions();
+            Logger = logger;
+
+            Client = new HttpClientEx();
+
+            if (string.IsNullOrEmpty(Options.OidPartner))
+            {
+                throw new ArgumentNullException(nameof(Options.OidPartner));
+            }
+
+            if (string.IsNullOrEmpty(Options.BusiPartner))
+            {
+                throw new ArgumentNullException(nameof(Options.BusiPartner));
+            }
+
+            if (string.IsNullOrEmpty(Options.RsaPrivateKey))
+            {
+                throw new ArgumentNullException(nameof(Options.RsaPrivateKey));
+            }
+
+            if (string.IsNullOrEmpty(Options.RsaPublicKey))
+            {
+                throw new ArgumentNullException(nameof(Options.RsaPublicKey));
+            }
+
+            RSAPrivateParameters = LianLianPaySignature.GetPrivateParameters(Options.RsaPrivateKey);
+            RSAPublicParameters = LianLianPaySignature.GetPublicParameters(Options.RsaPublicKey);
+        }
+
+        public void SetTimeout(int timeout)
+        {
+            Client.Timeout = new TimeSpan(0, 0, 0, timeout);
+        }
+
+        public async Task<T> ExecuteAsync<T>(ILianLianPayRequest<T> request) where T : LianLianPayResponse
+        {
+            // 字典排序
+            var txtParams = new LianLianPayDictionary(request.GetParameters())
+            {
+                { OID_PARTNER, Options.OidPartner },
+                { SIGN_TYPE, Options.SignType },
+            };
+
+            // 添加签名
+            var signContent = LianLianPaySignature.GetSignContent(txtParams);
+            txtParams.Add(SIGN, LianLianPaySignature.RSASignContent(signContent, RSAPrivateParameters));
+
+            var content = JsonConvert.SerializeObject(txtParams, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });
+            Logger.LogInformation(0, "Request:{content}", content);
+
+            var rspContent = await Client.DoPostAsync(request.GetRequestUrl(), content);
+            Logger.LogInformation(1, "Response:{content}", rspContent);
+
+            var parser = new LianLianPayJsonParser<T>();
+            var rsp = parser.Parse(rspContent);
+
+            // 不签名参数
+            var excludePara = new List<string>();
+            if (request is LianLianPayOrderQueryRequest)
+            {
+                excludePara.Add("bank_name");
+                excludePara.Add("card_no");
+            }
+            else if (request is LianLianPayQueryBankCarBindListRequest)
+            {
+                excludePara.Add("agreement_list");
+            }
+
+            CheckNotifySign(rsp.Parameters, excludePara, RSAPublicParameters);
+            return rsp;
+        }
+
+        public Task<T> PageExecuteAsync<T>(ILianLianPayRequest<T> request, string reqMethod) where T : LianLianPayResponse
+        {
+            var txtParams = new LianLianPayDictionary(request.GetParameters())
+            {
+                { OID_PARTNER, Options.OidPartner },
+                { SIGN_TYPE, Options.SignType },
+                { BUSI_PARTNER, Options.BusiPartner },
+                { TIMESTAMP, DateTime.Now },
+            };
+
+            // 添加签名
+            var signContent = LianLianPaySignature.GetSignContent(txtParams);
+            txtParams.Add(SIGN, LianLianPaySignature.RSASignContent(signContent, RSAPrivateParameters));
+
+            var body = string.Empty;
+
+            if (reqMethod == "GET")
+            {
+                //拼接get请求的url
+                var tmpUrl = request.GetRequestUrl();
+                if (txtParams != null && txtParams.Count > 0)
+                {
+                    if (tmpUrl.Contains("?"))
+                    {
+                        tmpUrl = tmpUrl + "&" + HttpClientEx.BuildQuery(txtParams);
+                    }
+                    else
+                    {
+                        tmpUrl = tmpUrl + "?" + HttpClientEx.BuildQuery(txtParams);
+                    }
+                }
+                body = tmpUrl;
+                Logger.LogInformation(0, "Request Url:{body}", body);
+            }
+            else
+            {
+                //输出post表单
+                body = BuildHtmlRequest(request.GetRequestUrl(), txtParams);
+                Logger.LogInformation(0, "Request Html:{body}", body);
+            }
+
+            var parser = new LianLianPayJsonParser<T>();
+            var rsp = parser.Parse(body);
+            return Task.FromResult(rsp);
+        }
+
+        #region ILianLianPayClient Members
+        public string BuildHtmlRequest(string url, IDictionary<string, string> sParaTemp)
+        {
+            //待请求参数数组
+            var dicPara = new Dictionary<string, string>(sParaTemp);
+
+            var sbHtml = new StringBuilder();
+            sbHtml.Append("<form id='submit' name='submit' action='" + url + "' method='post' style='display:none;'>");
+            foreach (var temp in dicPara)
+            {
+                sbHtml.Append("<input  name='" + temp.Key + "' value='" + temp.Value + "'/>");
+            }
+            sbHtml.Append("<input type='submit' style='display:none;'></form>");
+            //表单实现自动提交
+            sbHtml.Append("<script>document.forms['submit'].submit();</script>");
+
+            return sbHtml.ToString();
+        }
+        #endregion
+
+        private void CheckNotifySign(LianLianPayDictionary para, IList<string> excludePara, RSAParameters parameters)
+        {
+            if (para.Count == 0)
+            {
+                throw new Exception("sign check fail: para is Empty!");
+            }
+
+            if (para.TryGetValue("sign", out var sign))
+            {
+                var prestr = LianLianPaySignature.GetSignContent(para, excludePara);
+                if (!LianLianPaySignature.RSACheckContent(prestr, sign, parameters))
+                {
+                    throw new Exception("sign check fail: check Sign and Data Fail JSON also");
+                }
+            }
+        }
+    }
+}

+ 65 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/LianLianPayDictionary.cs

@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay
+{
+    public class LianLianPayDictionary : SortedDictionary<string, string>
+    {
+        private const string DATE_TIME_FORMAT = "yyyyMMddHHmmss";
+
+        public LianLianPayDictionary() { }
+
+        public LianLianPayDictionary(IDictionary<string, string> dictionary)
+            : base(dictionary)
+        { }
+
+        public void Add(string key, object value)
+        {
+            string strValue;
+
+            if (value == null)
+            {
+                strValue = null;
+            }
+            else if (value is string)
+            {
+                strValue = (string)value;
+            }
+            else if (value is DateTime?)
+            {
+                var dateTime = value as DateTime?;
+                strValue = dateTime.Value.ToString(DATE_TIME_FORMAT);
+            }
+            else if (value is int?)
+            {
+                strValue = (value as int?).Value.ToString();
+            }
+            else if (value is long?)
+            {
+                strValue = (value as long?).Value.ToString();
+            }
+            else if (value is double?)
+            {
+                strValue = (value as double?).Value.ToString();
+            }
+            else if (value is bool?)
+            {
+                strValue = (value as bool?).Value.ToString().ToLower();
+            }
+            else
+            {
+                strValue = value.ToString();
+            }
+
+            Add(key, strValue);
+        }
+
+        public new void Add(string key, string value)
+        {
+            if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
+            {
+                base.Add(key, value);
+            }
+        }
+    }
+}

+ 105 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/LianLianPayNotifyClient.cs

@@ -0,0 +1,105 @@
+using Essensoft.AspNetCore.Payment.LianLianPay.Parser;
+using Essensoft.AspNetCore.Payment.LianLianPay.Utility;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System;
+using System.IO;
+using System.Security.Cryptography;
+using System.Threading.Tasks;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay
+{
+    public class LianLianPayNotifyClient
+    {
+        private RSAParameters RSAPublicParameters;
+
+        public LianLianPayOptions Options { get; set; }
+
+        public virtual ILogger<LianLianPayClient> Logger { get; set; }
+
+        public LianLianPayNotifyClient(
+            IOptions<LianLianPayOptions> optionsAccessor,
+            ILogger<LianLianPayClient> logger)
+        {
+            Options = optionsAccessor?.Value ?? new LianLianPayOptions();
+            Logger = logger;
+
+            if (string.IsNullOrEmpty(Options.OidPartner))
+            {
+                throw new ArgumentNullException(nameof(Options.OidPartner));
+            }
+
+            if (string.IsNullOrEmpty(Options.BusiPartner))
+            {
+                throw new ArgumentNullException(nameof(Options.BusiPartner));
+            }
+
+            if (string.IsNullOrEmpty(Options.RsaPublicKey))
+            {
+                throw new ArgumentNullException(nameof(Options.RsaPublicKey));
+            }
+
+            RSAPublicParameters = LianLianPaySignature.GetPublicParameters(Options.RsaPublicKey);
+        }
+
+        public async Task<T> ExecuteAsync<T>(HttpRequest request) where T : LianLianPayNotifyResponse
+        {
+            if (request.HasFormContentType)
+            {
+                var parameters = await GetParametersAsync(request);
+                var query = HttpClientEx.BuildQuery(parameters);
+                Logger.LogInformation(0, "Request:{query}", query);
+
+                var parser = new LianLianPayDictionaryParser<T>();
+                var rsp = parser.Parse(parameters);
+                CheckNotifySign(parameters, RSAPublicParameters);
+                return rsp;
+            }
+            else if (request.HasTextJsonContentType())
+            {
+                var body = await new StreamReader(request.Body).ReadToEndAsync();
+                Logger.LogInformation(0, "Request:{body}", body);
+
+                var parser = new LianLianPayJsonParser<T>();
+                var rsp = parser.Parse(body);
+                CheckNotifySign(rsp.Parameters, RSAPublicParameters);
+                return rsp;
+            }
+            else
+            {
+                throw new Exception("sign check fail: check Sign and Data Fail!");
+            }
+        }
+
+        private async Task<LianLianPayDictionary> GetParametersAsync(HttpRequest request)
+        {
+            var parameters = new LianLianPayDictionary();
+            var form = await request.ReadFormAsync();
+            foreach (var item in form)
+            {
+                parameters.Add(item.Key, item.Value);
+            }
+            return parameters;
+        }
+
+        private void CheckNotifySign(LianLianPayDictionary para, RSAParameters parameters)
+        {
+            if (para.Count == 0)
+            {
+                throw new Exception("sign check fail: para is Empty!");
+            }
+
+            if (!para.TryGetValue("sign", out var sign))
+            {
+                throw new Exception("sign check fail: sign is Empty!");
+            }
+
+            var prestr = LianLianPaySignature.GetSignContent(para);
+            if (!LianLianPaySignature.RSACheckContent(prestr, sign, parameters))
+            {
+                throw new Exception("sign check fail: check Sign and Data Fail JSON also");
+            }
+        }
+    }
+}

+ 6 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/LianLianPayNotifyResponse.cs

@@ -0,0 +1,6 @@
+namespace Essensoft.AspNetCore.Payment.LianLianPay
+{
+    public abstract class LianLianPayNotifyResponse : LianLianPayResponse
+    {
+    }
+}

+ 6 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/LianLianPayObject.cs

@@ -0,0 +1,6 @@
+namespace Essensoft.AspNetCore.Payment.LianLianPay
+{
+    public abstract class LianLianPayObject
+    {
+    }
+}

+ 31 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/LianLianPayOptions.cs

@@ -0,0 +1,31 @@
+namespace Essensoft.AspNetCore.Payment.LianLianPay
+{
+    public class LianLianPayOptions
+    {
+        /// <summary>
+        /// 连连支付公钥
+        /// </summary>
+        public string RsaPublicKey { get; set; }
+
+        /// <summary>
+        /// 商户私钥
+        /// </summary>
+        public string RsaPrivateKey { get; set; }
+
+        /// <summary>
+        /// 商户号
+        /// </summary>
+        public string OidPartner { get; set; }
+
+        /// <summary>
+        /// 业务类型
+        /// 连连支付根据商户业务为商户开设的业务类型; (101001:虚拟商品销售、109001:实物商品销售、108001:外部账户充值)
+        /// </summary>
+        public string BusiPartner { get; set; }
+
+        /// <summary>
+        /// 签名方式
+        /// </summary>
+        public string SignType { get; } = "RSA";
+    }
+}

+ 19 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/LianLianPayResponse.cs

@@ -0,0 +1,19 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay
+{
+    public abstract class LianLianPayResponse : LianLianPayObject
+    {
+        /// <summary>
+        /// 响应原始内容
+        /// </summary>
+        [JsonIgnore]
+        public string Body { get; set; }
+
+        /// <summary>
+        /// 响应原始参数
+        /// </summary>
+        [JsonIgnore]
+        public LianLianPayDictionary Parameters { get; internal set; }
+    }
+}

+ 123 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/Notify/LianLianPayAuthPayNotifyResponse.cs

@@ -0,0 +1,123 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay.Notify
+{
+    public class LianLianPayAuthPayNotifyResponse : LianLianPayNotifyResponse
+    {
+        /// <summary>
+        /// 商户编号
+        /// 商户编号是商户在连连支付支付平台上开 设的商户号码,为18位数字,如: 201304121000001004 
+        /// </summary>
+        [JsonProperty("oid_partner")]
+        public string OidPartner { get; set; }
+
+        /// <summary>
+        /// 签名方式
+        /// </summary>
+        [JsonProperty("sign_type")]
+        public string SignType { get; set; }
+
+        /// <summary>
+        /// 签名
+        /// RSA加密签名,见安全签名机制 订单信息 
+        /// </summary>
+        [JsonProperty("sign")]
+        public string Sign { get; set; }
+
+        /// <summary>
+        /// 商户订单时间
+        /// 格式:YYYYMMDDH24MISS  14 位数 字,精确到秒 
+        /// </summary>
+        [JsonProperty("dt_order")]
+        public string DtOrder { get; set; }
+
+        /// <summary>
+        /// 商户唯一订单号
+        /// 商户系统唯一订单号 
+        /// </summary>
+        [JsonProperty("no_order")]
+        public string NoOrder { get; set; }
+
+        /// <summary>
+        /// 连连支付支付单号
+        /// 2011030900001098
+        /// </summary>
+        [JsonProperty("oid_paybill")]
+        public string OidPaybill { get; set; }
+
+        /// <summary>
+        /// 交易金额
+        /// 该笔订单的资金总额,单位为RMB-元。 大于0的数字,精确到小数点后两位。 如:49.65 
+        /// </summary>
+        [JsonProperty("money_order")]
+        public string MoneyOrder { get; set; }
+
+        /// <summary>
+        /// 支付结果
+        /// 支付结果以此为准,商户按此进行后续是否 发货操作 
+        /// </summary>
+        [JsonProperty("result_pay")]
+        public string ResultPay { get; set; }
+
+        /// <summary>
+        /// 清算日期
+        /// YYYYMMDD 支付成功后会有 
+        /// </summary>
+        [JsonProperty("settle_date")]
+        public string SettleDate { get; set; }
+
+        /// <summary>
+        /// 订单描述
+        /// </summary>
+        [JsonProperty("info_order")]
+        public string InfoOrder { get; set; }
+
+        /// <summary>
+        /// 支付方式
+        /// 1:网银支付(借记卡) 8:网银支付(信用卡) 9:B2B企业网银支付 
+        /// </summary>
+        [JsonProperty("pay_type")]
+        public string PayType { get; set; }
+
+        /// <summary>
+        /// 银行编号
+        /// 列表见附录
+        /// </summary>
+        [JsonProperty("bank_code")]
+        public string BankCode { get; set; }
+
+
+        /// <summary>
+        /// 签约协议号
+        /// 银通签约的协议编号
+        /// </summary>
+        [JsonProperty("no_agree")]
+        public string NoAgree { get; set; }
+
+        /// <summary>
+        /// 证件类型
+        /// </summary>
+        [JsonProperty("id_type")]
+        public string IdType { get; set; }
+
+        /// <summary>
+        /// 证件号码
+        /// </summary>
+        [JsonProperty("id_no")]
+        public string IdNo { get; set; }
+
+        /// <summary>
+        /// 银行账号姓名
+        /// </summary>
+        [JsonProperty("acct_name")]
+        public string AcctName { get; set; }
+
+        /// <summary>
+        /// 银行卡号
+        /// 显示前 6 后 4 隐藏其它
+        /// 例: 622208*********0000
+        /// </summary>
+        [JsonProperty("card_no")]
+        public string CardNo { get; set; }
+    }
+}

+ 89 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/Notify/LianLianPayAuthPayReturnResponse.cs

@@ -0,0 +1,89 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay.Notify
+{
+    public class LianLianPayAuthPayReturnResponse : LianLianPayNotifyResponse
+    {
+        /// <summary>
+        /// 商户编号
+        /// 商户编号是商户在连连支付支付平台上开 设的商户号码,为18位数字,如: 201304121000001004 
+        /// </summary>
+        [JsonProperty("oid_partner")]
+        public string OidPartner { get; set; }
+
+        /// <summary>
+        /// 签名方式
+        /// </summary>
+        [JsonProperty("sign_type")]
+        public string SignType { get; set; }
+
+        /// <summary>
+        /// 签名
+        /// RSA加密签名,见安全签名机制 订单信息 
+        /// </summary>
+        [JsonProperty("sign")]
+        public string Sign { get; set; }
+
+        /// <summary>
+        /// 商户订单时间
+        /// 格式:YYYYMMDDH24MISS  14 位数 字,精确到秒 
+        /// </summary>
+        [JsonProperty("dt_order")]
+        public string DtOrder { get; set; }
+
+        /// <summary>
+        /// 商户唯一订单号
+        /// 商户系统唯一订单号
+        /// </summary>
+        [JsonProperty("no_order")]
+        public string NoOrder { get; set; }
+
+        /// <summary>
+        /// 连连支付支付单号
+        /// 2011030900001098 
+        /// </summary>
+        [JsonProperty("oid_paybill")]
+        public string OidPaybill { get; set; }
+
+        /// <summary>
+        /// 交易金额
+        /// 该笔订单的资金总额,单位为RMB-元。 大于0的数字,精确到小数点后两位。 如:49.65 
+        /// </summary>
+        [JsonProperty("money_order")]
+        public string MoneyOrder { get; set; }
+
+        /// <summary>
+        /// 支付结果
+        /// 支付结果以此为准,商户按此进行后续是否 发货操作 
+        /// </summary>
+        [JsonProperty("result_pay")]
+        public string ResultPay { get; set; }
+
+        /// <summary>
+        /// 清算日期
+        /// 支付成功后会有
+        /// </summary>
+        [JsonProperty("settle_date")]
+        public string SettleDate { get; set; }
+
+        /// <summary>
+        /// 订单描述
+        /// </summary>
+        [JsonProperty("info_order")]
+        public string InfoOrder { get; set; }
+
+        /// <summary>
+        /// 支付方式
+        /// 1:网银支付(借记卡) 8:网银支付(信用卡) 9:B2B企业网银支付
+        /// </summary>
+        [JsonProperty("pay_type")]
+        public string PayType { get; set; }
+
+        /// <summary>
+        /// 银行编号
+        /// 列表见附录,余额支付没有此项
+        /// </summary>
+        [JsonProperty("bank_code")]
+        public string BankCode { get; set; }
+    }
+}

+ 89 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/Notify/LianLianPayBankPayNotifyResponse.cs

@@ -0,0 +1,89 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay.Notify
+{
+    public class LianLianPayBankPayNotifyResponse : LianLianPayNotifyResponse
+    {
+        /// <summary>
+        /// 商户编号
+        /// 商户编号是商户在连连支付支付平台上开 设的商户号码,为18位数字,如: 201304121000001004 
+        /// </summary>
+        [JsonProperty("oid_partner")]
+        public string OidPartner { get; set; }
+
+        /// <summary>
+        /// 签名方式
+        /// </summary>
+        [JsonProperty("sign_type")]
+        public string SignType { get; set; }
+
+        /// <summary>
+        /// 签名
+        /// RSA加密签名,见安全签名机制 订单信息 
+        /// </summary>
+        [JsonProperty("sign")]
+        public string Sign { get; set; }
+
+        /// <summary>
+        /// 商户订单时间
+        /// 格式:YYYYMMDDH24MISS  14 位数 字,精确到秒 
+        /// </summary>
+        [JsonProperty("dt_order")]
+        public string DtOrder { get; set; }
+
+        /// <summary>
+        /// 商户唯一订单号
+        /// 商户系统唯一订单号 
+        /// </summary>
+        [JsonProperty("no_order")]
+        public string NoOrder { get; set; }
+
+        /// <summary>
+        /// 连连支付支付单号
+        /// 2011030900001098
+        /// </summary>
+        [JsonProperty("oid_paybill")]
+        public string OidPaybill { get; set; }
+
+        /// <summary>
+        /// 交易金额
+        /// 该笔订单的资金总额,单位为RMB-元。 大于0的数字,精确到小数点后两位。 如:49.65 
+        /// </summary>
+        [JsonProperty("money_order")]
+        public string MoneyOrder { get; set; }
+
+        /// <summary>
+        /// 支付结果
+        /// 支付结果以此为准,商户按此进行后续是否 发货操作 
+        /// </summary>
+        [JsonProperty("result_pay")]
+        public string ResultPay { get; set; }
+
+        /// <summary>
+        /// 清算日期
+        /// YYYYMMDD 支付成功后会有 
+        /// </summary>
+        [JsonProperty("settle_date")]
+        public string SettleDate { get; set; }
+
+        /// <summary>
+        /// 订单描述
+        /// </summary>
+        [JsonProperty("info_order")]
+        public string InfoOrder { get; set; }
+
+        /// <summary>
+        /// 支付方式
+        /// 1:网银支付(借记卡) 8:网银支付(信用卡) 9:B2B企业网银支付 
+        /// </summary>
+        [JsonProperty("pay_type")]
+        public string PayType { get; set; }
+
+        /// <summary>
+        /// 银行编号
+        /// 列表见附录
+        /// </summary>
+        [JsonProperty("bank_code")]
+        public string BankCode { get; set; }
+    }
+}

+ 89 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/Notify/LianLianPayBankPayReturnResponse.cs

@@ -0,0 +1,89 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay.Notify
+{
+    public class LianLianPayBankPayReturnResponse : LianLianPayNotifyResponse
+    {
+        /// <summary>
+        /// 商户编号
+        /// 商户编号是商户在连连支付支付平台上开 设的商户号码,为18位数字,如: 201304121000001004 
+        /// </summary>
+        [JsonProperty("oid_partner")]
+        public string OidPartner { get; set; }
+
+        /// <summary>
+        /// 签名方式
+        /// </summary>
+        [JsonProperty("sign_type")]
+        public string SignType { get; set; }
+
+        /// <summary>
+        /// 签名
+        /// RSA加密签名,见安全签名机制 订单信息 
+        /// </summary>
+        [JsonProperty("sign")]
+        public string Sign { get; set; }
+
+        /// <summary>
+        /// 商户订单时间
+        /// 格式:YYYYMMDDH24MISS  14 位数 字,精确到秒 
+        /// </summary>
+        [JsonProperty("dt_order")]
+        public string DtOrder { get; set; }
+
+        /// <summary>
+        /// 商户唯一订单号
+        /// 商户系统唯一订单号
+        /// </summary>
+        [JsonProperty("no_order")]
+        public string NoOrder { get; set; }
+
+        /// <summary>
+        /// 连连支付支付单号
+        /// 2011030900001098 
+        /// </summary>
+        [JsonProperty("oid_paybill")]
+        public string OidPaybill { get; set; }
+
+        /// <summary>
+        /// 交易金额
+        /// 该笔订单的资金总额,单位为RMB-元。 大于0的数字,精确到小数点后两位。 如:49.65 
+        /// </summary>
+        [JsonProperty("money_order")]
+        public string MoneyOrder { get; set; }
+
+        /// <summary>
+        /// 支付结果
+        /// 支付结果以此为准,商户按此进行后续是否 发货操作 
+        /// </summary>
+        [JsonProperty("result_pay")]
+        public string ResultPay { get; set; }
+
+        /// <summary>
+        /// 清算日期
+        /// 支付成功后会有
+        /// </summary>
+        [JsonProperty("settle_date")]
+        public string SettleDate { get; set; }
+
+        /// <summary>
+        /// 订单描述
+        /// </summary>
+        [JsonProperty("info_order")]
+        public string InfoOrder { get; set; }
+
+        /// <summary>
+        /// 支付方式
+        /// 1:网银支付(借记卡) 8:网银支付(信用卡) 9:B2B企业网银支付
+        /// </summary>
+        [JsonProperty("pay_type")]
+        public string PayType { get; set; }
+
+        /// <summary>
+        /// 银行编号
+        /// 列表见附录,余额支付没有此项
+        /// </summary>
+        [JsonProperty("bank_code")]
+        public string BankCode { get; set; }
+    }
+}

+ 115 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/Notify/LianLianPayQuickPayNotifyResponse.cs

@@ -0,0 +1,115 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay.Notify
+{
+    public class LianLianPayQuickPayNotifyResponse : LianLianPayNotifyResponse
+    {
+        /// <summary>
+        /// 商户编号
+        /// 商户编号是商户在连连支付支付平台上开 设的商户号码,为18位数字,如: 201304121000001004 
+        /// </summary>
+        [JsonProperty("oid_partner")]
+        public string OidPartner { get; set; }
+
+        /// <summary>
+        /// 签名方式
+        /// </summary>
+        [JsonProperty("sign_type")]
+        public string SignType { get; set; }
+
+        /// <summary>
+        /// 签名
+        /// RSA加密签名,见安全签名机制 订单信息 
+        /// </summary>
+        [JsonProperty("sign")]
+        public string Sign { get; set; }
+
+        /// <summary>
+        /// 商户订单时间
+        /// 格式:YYYYMMDDH24MISS  14 位数 字,精确到秒 
+        /// </summary>
+        [JsonProperty("dt_order")]
+        public string DtOrder { get; set; }
+
+        /// <summary>
+        /// 商户唯一订单号
+        /// 商户系统唯一订单号 
+        /// </summary>
+        [JsonProperty("no_order")]
+        public string NoOrder { get; set; }
+
+        /// <summary>
+        /// 连连支付支付单号
+        /// 2011030900001098
+        /// </summary>
+        [JsonProperty("oid_paybill")]
+        public string OidPaybill { get; set; }
+
+        /// <summary>
+        /// 交易金额
+        /// 该笔订单的资金总额,单位为RMB-元。 大于0的数字,精确到小数点后两位。 如:49.65 
+        /// </summary>
+        [JsonProperty("money_order")]
+        public string MoneyOrder { get; set; }
+
+        /// <summary>
+        /// 支付结果
+        /// 支付结果以此为准,商户按此进行后续是否 发货操作 
+        /// </summary>
+        [JsonProperty("result_pay")]
+        public string ResultPay { get; set; }
+
+        /// <summary>
+        /// 清算日期
+        /// YYYYMMDD 支付成功后会有 
+        /// </summary>
+        [JsonProperty("settle_date")]
+        public string SettleDate { get; set; }
+
+        /// <summary>
+        /// 订单描述
+        /// </summary>
+        [JsonProperty("info_order")]
+        public string InfoOrder { get; set; }
+
+        /// <summary>
+        /// 支付方式
+        /// 1:网银支付(借记卡) 8:网银支付(信用卡) 9:B2B企业网银支付 
+        /// </summary>
+        [JsonProperty("pay_type")]
+        public string PayType { get; set; }
+
+        /// <summary>
+        /// 银行编号
+        /// 列表见附录
+        /// </summary>
+        [JsonProperty("bank_code")]
+        public string BankCode { get; set; }
+
+
+        /// <summary>
+        /// 签约协议号
+        /// 银通签约的协议编号
+        /// </summary>
+        [JsonProperty("no_agree")]
+        public string NoAgree { get; set; }
+
+        /// <summary>
+        /// 证件类型
+        /// </summary>
+        [JsonProperty("id_type")]
+        public string IdType { get; set; }
+
+        /// <summary>
+        /// 证件号码
+        /// </summary>
+        [JsonProperty("id_no")]
+        public string IdNo { get; set; }
+
+        /// <summary>
+        /// 银行账号姓名
+        /// </summary>
+        [JsonProperty("acct_name")]
+        public string AcctName { get; set; }
+    }
+}

+ 89 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/Notify/LianLianPayQuickPayReturnResponse.cs

@@ -0,0 +1,89 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay.Notify
+{
+    public class LianLianPayQuickPayReturnResponse : LianLianPayNotifyResponse
+    {
+        /// <summary>
+        /// 商户编号
+        /// 商户编号是商户在连连支付支付平台上开 设的商户号码,为18位数字,如: 201304121000001004 
+        /// </summary>
+        [JsonProperty("oid_partner")]
+        public string OidPartner { get; set; }
+
+        /// <summary>
+        /// 签名方式
+        /// </summary>
+        [JsonProperty("sign_type")]
+        public string SignType { get; set; }
+
+        /// <summary>
+        /// 签名
+        /// RSA加密签名,见安全签名机制 订单信息 
+        /// </summary>
+        [JsonProperty("sign")]
+        public string Sign { get; set; }
+
+        /// <summary>
+        /// 商户订单时间
+        /// 格式:YYYYMMDDH24MISS  14 位数 字,精确到秒 
+        /// </summary>
+        [JsonProperty("dt_order")]
+        public string DtOrder { get; set; }
+
+        /// <summary>
+        /// 商户唯一订单号
+        /// 商户系统唯一订单号
+        /// </summary>
+        [JsonProperty("no_order")]
+        public string NoOrder { get; set; }
+
+        /// <summary>
+        /// 连连支付支付单号
+        /// 2011030900001098 
+        /// </summary>
+        [JsonProperty("oid_paybill")]
+        public string OidPaybill { get; set; }
+
+        /// <summary>
+        /// 交易金额
+        /// 该笔订单的资金总额,单位为RMB-元。 大于0的数字,精确到小数点后两位。 如:49.65 
+        /// </summary>
+        [JsonProperty("money_order")]
+        public string MoneyOrder { get; set; }
+
+        /// <summary>
+        /// 支付结果
+        /// 支付结果以此为准,商户按此进行后续是否 发货操作 
+        /// </summary>
+        [JsonProperty("result_pay")]
+        public string ResultPay { get; set; }
+
+        /// <summary>
+        /// 清算日期
+        /// 支付成功后会有
+        /// </summary>
+        [JsonProperty("settle_date")]
+        public string SettleDate { get; set; }
+
+        /// <summary>
+        /// 订单描述
+        /// </summary>
+        [JsonProperty("info_order")]
+        public string InfoOrder { get; set; }
+
+        /// <summary>
+        /// 支付方式
+        /// 1:网银支付(借记卡) 8:网银支付(信用卡) 9:B2B企业网银支付
+        /// </summary>
+        [JsonProperty("pay_type")]
+        public string PayType { get; set; }
+
+        /// <summary>
+        /// 银行编号
+        /// 列表见附录,余额支付没有此项
+        /// </summary>
+        [JsonProperty("bank_code")]
+        public string BankCode { get; set; }
+    }
+}

+ 70 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/Notify/LianLianPayRefundNotifyResponse.cs

@@ -0,0 +1,70 @@
+using Newtonsoft.Json;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay.Notify
+{
+    public class LianLianPayRefundNotifyResponse : LianLianPayNotifyResponse
+    {
+        /// <summary>
+        /// 商户编号
+        /// 商户编号是商户在连连支付支付平台上开 设的商户号码,为18位数字,如: 201304121000001004 
+        /// </summary>
+        [JsonProperty("oid_partner")]
+        public string OidPartner { get; set; }
+
+        /// <summary>
+        /// 签名方式
+        /// </summary>
+        [JsonProperty("sign_type")]
+        public string SignType { get; set; }
+
+        /// <summary>
+        /// 签名
+        /// RSA加密签名,见安全签名机制 订单信息 
+        /// </summary>
+        [JsonProperty("sign")]
+        public string Sign { get; set; }
+
+        /// <summary>
+        /// 商户退款流水号
+        /// 商户系统唯一标识该退款的流水号
+        /// </summary>
+        [JsonProperty("no_refund")]
+        public string NoRefund { get; set; }
+
+        /// <summary>
+        /// 商户退款时间
+        /// 格式:YYYYMMDDH24MISS 14 位数字,精确到秒
+        /// </summary>
+        [JsonProperty("dt_refund")]
+        public string DtRefund { get; set; }
+
+        /// <summary>
+        /// 退款金额
+        /// 退款金额,该金额必须小于或等于原订单金额,单位为 RMB-元。大于 0 的数字,精确到小数点后两位。如:49.65
+        /// </summary>
+        [JsonProperty("money_refund")]
+        public string MoneyRefund { get; set; }
+
+        /// <summary>
+        /// 连连银通退款流水号
+        /// 银通退款流水号
+        /// </summary>
+        [JsonProperty("oid_refundno")]
+        public string OidRefundNo { get; set; }
+
+        /// <summary>
+        /// 退款状态
+        /// 退款成功:2
+        /// 退款失败:3
+        /// </summary>
+        [JsonProperty("sta_refund")]
+        public string StaRefund { get; set; }
+
+        /// <summary>
+        /// 清算日期
+        /// 退货成功时返回
+        /// </summary>
+        [JsonProperty("settle_date")]
+        public string SettleDate { get; set; }
+    }
+}

+ 16 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/Parser/ILianLianPayParser.cs

@@ -0,0 +1,16 @@
+namespace Essensoft.AspNetCore.Payment.LianLianPay.Parser
+{
+    /// <summary>
+    /// LianLianPay API响应解释器接口。
+    /// </summary>
+    /// <typeparam name="T">领域对象</typeparam>
+    public interface ILianLianPayParser<T> where T : LianLianPayResponse
+    {
+        /// <summary>
+        /// 把响应字符串解释成相应的领域对象。
+        /// </summary>
+        /// <param name="body">响应字符串</param>
+        /// <returns>领域对象</returns>
+        T Parse(string body);
+    }
+}

+ 29 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/Parser/LianLianPayDictionaryParser.cs

@@ -0,0 +1,29 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay.Parser
+{
+    public class LianLianPayDictionaryParser<T> where T : LianLianPayResponse
+    {
+        public T Parse(IDictionary dic)
+        {
+            if (dic == null || dic.Count == 0)
+                throw new ArgumentNullException(nameof(dic));
+
+            T rsp = null;
+
+            try
+            {
+                var jsonText = JsonConvert.SerializeObject(dic);
+                rsp = JsonConvert.DeserializeObject<T>(jsonText);
+            }
+            catch { }
+
+            if (rsp == null)
+                rsp = Activator.CreateInstance<T>();
+
+            return rsp;
+        }
+    }
+}

+ 39 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/Parser/LianLianPayJsonParser.cs

@@ -0,0 +1,39 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay.Parser
+{
+    /// <summary>
+    /// LianLianPay JSON响应通用解释器。
+    /// </summary>
+    public class LianLianPayJsonParser<T> : ILianLianPayParser<T> where T : LianLianPayResponse
+    {
+        #region ILianLianPayParser<T> Members
+        public T Parse(string body)
+        {
+            T rsp = null;
+            try
+            {
+                rsp = JsonConvert.DeserializeObject<T>(body);
+
+                rsp.Parameters = new LianLianPayDictionary();
+                var objdic = JsonConvert.DeserializeObject<Dictionary<string, object>>(body);
+                foreach (var iter in objdic)
+                {
+                    rsp.Parameters.Add(iter.Key, iter.Value);
+                }
+            }
+            catch { }
+
+            if (rsp == null)
+                rsp = Activator.CreateInstance<T>();
+
+            if (rsp != null)
+                rsp.Body = body;
+
+            return rsp;
+        }
+        #endregion
+    }
+}

+ 175 - 0
src/Essensoft.AspNetCore.Payment.LianLianPay/Request/LianLianPayAuthPayRequest.cs

@@ -0,0 +1,175 @@
+using Essensoft.AspNetCore.Payment.LianLianPay.Response;
+using System.Collections.Generic;
+
+namespace Essensoft.AspNetCore.Payment.LianLianPay.Request
+{
+    public class LianLianPayAuthPayRequest : ILianLianPayRequest<LianLianPayAuthPayResponse>
+    {
+        /// <summary>
+        /// 平台来源标识
+        /// </summary>
+        public string Platform { get; set; }
+
+        /// <summary>
+        /// 用户ID
+        /// </summary>
+        public string UserId { get; set; }
+
+        /// <summary>
+        /// 商户唯一订单号
+        /// </summary>
+        public string NoOrder { get; set; }
+
+        /// <summary>
+        /// 商户订单时间
+        /// </summary>
+        public string DtOrder { get; set; }
+
+        /// <summary>
+        /// 商品名称
+        /// </summary>
+        public string NameGoods { get; set; }
+
+        /// <summary>
+        /// 订单描述
+        /// </summary>
+        public string InfoOrder { get; set; }
+
+        /// <summary>
+        /// 交易金额
+        /// 单位为RMB-元
+        /// </summary>
+        public string MoneyOrder { get; set; }
+
+        /// <summary>
+        /// 异步通知url
+        /// </summary>
+        public string NotifyUrl { get; set; }
+
+        /// <summary>
+        /// 同步跳转url
+        /// </summary>
+        public string UrlReturn { get; set; }
+
+        /// <summary>
+        /// 用户端申请IP
+        /// </summary>
+        public string UserreqIp { get; set; }
+
+        /// <summary>
+        /// 订单地址
+        /// </summary>
+        public string UrlOrder { get; set; }
+
+        /// <summary>
+        /// 订单有效时间
+        /// </summary>
+        public string ValidOrder { get; set; }
+
+        /// <summary>
+        /// 指定银行网银编号
+        /// </summary>
+        public string BankCode { get; set; }
+
+        /// <summary>
+        /// 支付方式
+        /// D 认证支付
+        /// 此支付方式与指定银行网银编号配合使用
+        /// </summary>
+        public string PayType { get; set; } = "D";
+
+        /// <summary>
+        /// 签约协议号
+        /// </summary>
+        public string NoAgree { get; set; }
+
+        /// <summary>
+        /// 分账信息数据
+        /// </summary>
+        public string ShareingData { get; set; }
+
+        /// <summary>
+        /// 风险控制参数
+        /// </summary>
+        public string RiskItem { get; set; }
+
+        /// <summary>
+        /// 证件类型
+        /// 默认为 0
+        /// 0:身份证
+        /// </summary>
+        public string IdType { get; set; }
+
+        /// <summary>
+        /// 证件号码
+        /// </summary>
+        public string IdNo { get; set; }
+
+        /// <summary>
+        /// 银行账号姓名
+        /// </summary>
+        public string AcctName { get; set; }
+
+        /// <summary>
+        /// 银行卡号
+        /// </summary>
+        public string CardNo { get; set; }
+
+        /// <summary>
+        /// 返回修改信息地址
+        /// </summary>
+        public string BackUrl { get; set; }
+
+        #region ILianLianPayRequest
+
+        private string Version = "1.0";
+
+        public string GetRequestUrl()
+        {
+            return "https://cashier.lianlianpay.com/payment/authpay.htm";
+        }
+
+        public IDictionary<string, string> GetParameters()
+        {
+            var parameters = new LianLianPayDictionary
+            {
+                { "version", Version },
+                { "platform", Platform },
+                { "user_id", UserId },
+                { "no_order", NoOrder },
+                { "dt_order", DtOrder },
+                { "name_goods", NameGoods },
+                { "info_order", InfoOrder },
+                { "money_order", MoneyOrder },
+                { "notify_url", NotifyUrl },
+                { "url_return", UrlReturn },
+                { "userreq_ip", UserreqIp?.Replace(".", "_") },
+                { "url_order", UrlOrder },
+                { "valid_order", ValidOrder },
+                { "bank_code", BankCode },
+                { "pay_type", PayType },
+                { "no_agree", NoAgree },
+                { "shareing_data", ShareingData },
+                { "risk_item", RiskItem },
+                { "id_type", IdType },
+                { "id_no", IdNo },
+                { "acct_name", AcctName },
+                { "card_no", CardNo },
+                { "back_url", BackUrl },
+            };
+            return parameters;
+        }
+
+        public string GetApiVersion()
+        {
+            return Version;
+        }
+
+        public void SetApiVersion(string apiVersion)
+        {
+            Version = apiVersion;
+        }
+
+        #endregion
+    }
+}

部分文件因为文件数量过多而无法显示