sunpengfei
11 小时以前 ab9b84ee42c872cd2277d2e3a863718355bcc6aa
feat:开发
6个文件已修改
5个文件已添加
851 ■■■■■ 已修改文件
ApiTools.Application/ApiTools.Application.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Application/ChannelWallets/Commands/ChannelWalletCommandHandler.cs 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/ApiTools.Core.xml 266 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Models/ChannelWallets/Commands/TestNongYePayCommand.cs 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Utils/NongYePayUtils/Models/NongYePayBaseRequest.cs 180 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Utils/NongYePayUtils/Models/NongYePayGetBalanceRequest.cs 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Utils/NongYePayUtils/NongYePayOptions.cs 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Utils/NongYePayUtils/NongYePayUtils.cs 181 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Utils/StringUtils/StringUtils.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Web.Entry/Startup.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Web.Entry/appsettings.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Application/ApiTools.Application.xml
@@ -165,6 +165,14 @@
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Application.ChannelWalletCommandHandler.Handle(ApiTools.Core.TestNongYePayCommand,System.Threading.CancellationToken)">
            <summary>
            测试农业银行接口
            </summary>
            <param name="request"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="T:ApiTools.Application.ChannelWalletQueryHandler">
            <summary>
            查询渠道钱包交易详情
ApiTools.Application/ChannelWallets/Commands/ChannelWalletCommandHandler.cs
@@ -19,15 +19,18 @@
            IDistributedLockProvider distributedLockProvider,
            ChannelWalletRepository channelWalletRepository,
            ChannelWalletTransactionRepository channelWalletTransactionRepository,
            ChannelWalletService channelWalletService
            ChannelWalletService channelWalletService,
            NongYePayUtils nongYePayUtils
        ) :
        IRequestHandler<SaveChannelPingAnPayWalletCommand, SaveChannelPingAnPayWalletCommandResult>,
        IRequestHandler<SubmitChannelWalletTransferCommand, SubmitChannelWalletTransferCommandResult>
        IRequestHandler<SubmitChannelWalletTransferCommand, SubmitChannelWalletTransferCommandResult>,
        IRequestHandler<TestNongYePayCommand, bool>
    {
        private readonly IDistributedLockProvider distributedLockProvider = distributedLockProvider;
        private readonly ChannelWalletRepository channelWalletRepository = channelWalletRepository;
        private readonly ChannelWalletTransactionRepository channelWalletTransactionRepository = channelWalletTransactionRepository;
        private readonly ChannelWalletService channelWalletService = channelWalletService;
        private readonly NongYePayUtils nongYePayUtils = nongYePayUtils;
        /// <summary>
        /// 保存渠道平安银行钱包
@@ -171,5 +174,25 @@
                FailReason = transaction.FailReason,
            };
        }
        /// <summary>
        /// 测试农业银行接口
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<bool> Handle(TestNongYePayCommand request, CancellationToken cancellationToken)
        {
            var res = await nongYePayUtils.GetBalance(new Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceRequest
            {
                Cmp = new Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceRequestCmp
                {
                    AccountNo = "314101046433493",
                    CurrencyCode = "01",
                    ProvinceCode = "14"
                }
            });
            return true;
        }
    }
}
ApiTools.Core/ApiTools.Core.xml
@@ -2473,6 +2473,11 @@
            查询到的订单状态为FAIL失败或REFUND退票时,返回具体的原因。
            </summary>
        </member>
        <member name="T:ApiTools.Core.TestNongYePayCommand">
            <summary>
            测试农业银行接口
            </summary>
        </member>
        <member name="T:ApiTools.Core.GetChannelPingAnPayWalletQuery">
            <summary>
            查询渠道平安银行钱包
@@ -4937,6 +4942,231 @@
            </summary>
            <returns></returns>
        </member>
        <member name="T:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseRequest">
            <summary>
            农业银行支付基础请求
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseRequest.TransCode">
            <summary>
            交易码
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseRequest.CorpNo">
            <summary>
            客户号
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseRequest.OpNo">
            <summary>
            操作员ID(空节点,ICT自动补充)
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseRequest.AuthNo">
            <summary>
            认证码(空节点,ICT自动补充)
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseRequest.ChannelType">
            <summary>
            渠道标识
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseRequest.ProductID">
            <summary>
            产品标识
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseRequest.ReqDate">
            <summary>
            请求日期(YYYYMMDD)
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseRequest.ReqTime">
            <summary>
            请求时间(HHMMSS)
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseRequest.ReqSeqNo">
            <summary>
            请求流水号(全局唯一)
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseRequest.Sign">
            <summary>
            数字签名(空节点,ICT自动补充)
            </summary>
        </member>
        <member name="T:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponse">
            <summary>
            农业银行支付基础回调
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponse.TransCode">
            <summary>
            交易码
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponse.RespSource">
            <summary>
            返回来源(0=成功)
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponse.RespSeqNo">
            <summary>
            应答流水号
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponse.RespCode">
            <summary>
            返回码(0000=受理成功)
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponse.RespInfo">
            <summary>
            返回信息
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponse.RxtInfo">
            <summary>
            扩展信息
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponse.RespDate">
            <summary>
            应答日期
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponse.RespTime">
            <summary>
            应答时间
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponse.FileFlag">
            <summary>
            文件标识
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponse.Cmp">
            <summary>
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponse.Cme">
            <summary>
            </summary>
        </member>
        <member name="T:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponseCme">
            <summary>
            农业银行支付基础回调
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponseCme.RecordNum">
            <summary>
            记录数(行)
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponseCme.FieldNum">
            <summary>
            字段数(列)
            </summary>
        </member>
        <member name="T:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponseCmp">
            <summary>
            农业银行支付基础回调
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponseCmp.BatFileName">
            <summary>
            文件名
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayBaseResponseCmp.RespPrvData">
            <summary>
            私有数据区
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceRequest.Cmp">
            <summary>
            业务数据
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceRequestCmp.ProvinceCode">
            <summary>
            省市代码
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceRequestCmp.AccountNo">
            <summary>
            查询账号
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceRequestCmp.CurrencyCode">
            <summary>
            货币码
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceResponseCorp.DbAccName">
            <summary>
            借方户名
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceResponseAcc.Bal">
            <summary>
            账户余额
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceResponseAcc.AvailBal">
            <summary>
            账户可用余额
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceResponseAcc.FrzAmt">
            <summary>
            冻结金额
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceResponseAcc.FrzBal">
            <summary>
            冻结余额
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceResponseAcc.ValUDLmt">
            <summary>
            不定期可用限额
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceResponseAcc.ValMonthLmt">
            <summary>
            月可用限额
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceResponseAcc.ValDayLmt">
            <summary>
            日可用限额
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceResponseAcc.LastAvailBal">
            <summary>
            昨日可用余额
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceResponseAcc.LastBal">
            <summary>
            昨日余额
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceResponseAcc.AccType">
            <summary>
            账户类型
            </summary>
        </member>
        <member name="P:ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceResponseAcc.AccSts">
            <summary>
            账户状态
            </summary>
        </member>
        <member name="T:ApiTools.Core.Utils.WxmpUtils.WxmpGetAccessTokenRequest">
            <summary>
            微信小程序获取接口调用凭据
@@ -5057,6 +5287,42 @@
            </summary>
            <returns></returns>
        </member>
        <member name="P:ApiTools.Core.NongYePayOptions.Ip">
            <summary>
            ICT IP地址
            </summary>
        </member>
        <member name="P:ApiTools.Core.NongYePayOptions.Port">
            <summary>
            ICP 端口
            </summary>
        </member>
        <member name="P:ApiTools.Core.NongYePayOptions.CorpNo">
            <summary>
            客户号
            </summary>
        </member>
        <member name="M:ApiTools.Core.NongYePayUtils.GetBalance(ApiTools.Core.Utils.NongYePayUtils.Models.NongYePayGetBalanceRequest)">
            <summary>
            查询账户余额
            </summary>
            <returns>余额信息</returns>
        </member>
        <member name="M:ApiTools.Core.NongYePayUtils.SerializeRequest``1(``0)">
            <summary>
            泛型请求类转XML
            </summary>
        </member>
        <member name="M:ApiTools.Core.NongYePayUtils.DeserializeResponse``1(System.String)">
            <summary>
            XML转泛型应答类
            </summary>
        </member>
        <member name="M:ApiTools.Core.NongYePayUtils.SendRequest(System.String)">
            <summary>
            发送请求并接收应答
            </summary>
        </member>
        <member name="T:ApiTools.Core.PasswordUtils">
            <summary>
            密码工具
ApiTools.Core/Models/ChannelWallets/Commands/TestNongYePayCommand.cs
New file
@@ -0,0 +1,17 @@
using MediatR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 测试农业银行接口
    /// </summary>
    [Resource([EnumResourceController.UserServerChannelWallet])]
    public class TestNongYePayCommand : IRequest<bool>
    {
    }
}
ApiTools.Core/Utils/NongYePayUtils/Models/NongYePayBaseRequest.cs
New file
@@ -0,0 +1,180 @@
using Org.BouncyCastle.Ocsp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace ApiTools.Core.Utils.NongYePayUtils.Models
{
    /// <summary>
    /// 农业银行支付基础请求
    /// </summary>
    [XmlRoot("ap")]
    public abstract class NongYePayBaseRequest
    {
        /// <summary>
        /// 交易码
        /// </summary>
        [XmlElement("CCTransCode")]
        public string TransCode { get; set; }
        /// <summary>
        /// 客户号
        /// </summary>
        [XmlElement("CorpNo")]
        public string CorpNo { get; set; }
        /// <summary>
        /// 操作员ID(空节点,ICT自动补充)
        /// </summary>
        [XmlElement("OpNo")]
        public string OpNo { get; set; }
        /// <summary>
        /// 认证码(空节点,ICT自动补充)
        /// </summary>
        [XmlElement("AuthNo")]
        public string AuthNo { get; set; }
        /// <summary>
        /// 渠道标识
        /// </summary>
        [XmlElement("ChannelType")]
        public string ChannelType { get; set; }
        /// <summary>
        /// 产品标识
        /// </summary>
        [XmlElement("ProductID")]
        public string ProductID { get; set; }
        /// <summary>
        /// 请求日期(YYYYMMDD)
        /// </summary>
        [XmlElement("ReqDate")]
        public string ReqDate { get; set; }
        /// <summary>
        /// 请求时间(HHMMSS)
        /// </summary>
        [XmlElement("ReqTime")]
        public string ReqTime { get; set; }
        /// <summary>
        /// 请求流水号(全局唯一)
        /// </summary>
        [XmlElement("ReqSeqNo")]
        public string ReqSeqNo { get; set; }
        /// <summary>
        /// 数字签名(空节点,ICT自动补充)
        /// </summary>
        [XmlElement("Sign")]
        public string Sign { get; set; }
    }
    /// <summary>
    /// 农业银行支付基础回调
    /// </summary>
    [XmlRoot("ap")]
    public abstract class NongYePayBaseResponse
    {
        /// <summary>
        /// 交易码
        /// </summary>
        [XmlElement("CCTransCode")]
        public string TransCode { get; set; }
        /// <summary>
        /// 返回来源(0=成功)
        /// </summary>
        [XmlElement("RespSource")]
        public string RespSource { get; set; }
        /// <summary>
        /// 应答流水号
        /// </summary>
        [XmlElement("RespSeqNo")]
        public string RespSeqNo { get; set; }
        /// <summary>
        /// 返回码(0000=受理成功)
        /// </summary>
        [XmlElement("RespCode")]
        public string RespCode { get; set; }
        /// <summary>
        /// 返回信息
        /// </summary>
        [XmlElement("RespInfo")]
        public string RespInfo { get; set; }
        /// <summary>
        /// 扩展信息
        /// </summary>
        [XmlElement("RxtInfo")]
        public string RxtInfo { get; set; }
        /// <summary>
        /// 应答日期
        /// </summary>
        [XmlElement("RespDate")]
        public string RespDate { get; set; }
        /// <summary>
        /// 应答时间
        /// </summary>
        [XmlElement("RespTime")]
        public string RespTime { get; set; }
        /// <summary>
        /// 文件标识
        /// </summary>
        [XmlElement("FileFlag")]
        public string FileFlag { get; set; }
        /// <summary>
        ///
        /// </summary>
        public NongYePayBaseResponseCmp Cmp { get; set; }
        /// <summary>
        ///
        /// </summary>
        public NongYePayBaseResponseCme Cme { get; set; }
    }
    /// <summary>
    /// 农业银行支付基础回调
    /// </summary>
    public class NongYePayBaseResponseCme
    {
        /// <summary>
        /// 记录数(行)
        /// </summary>
        public string RecordNum { get; set; }
        /// <summary>
        /// 字段数(列)
        /// </summary>
        public string FieldNum { get; set; }
    }
    /// <summary>
    /// 农业银行支付基础回调
    /// </summary>
    public class NongYePayBaseResponseCmp
    {
        /// <summary>
        /// 文件名
        /// </summary>
        public string BatFileName { get; set; }
        /// <summary>
        /// 私有数据区
        /// </summary>
        public string RespPrvData { get; set; }
    }
}
ApiTools.Core/Utils/NongYePayUtils/Models/NongYePayGetBalanceRequest.cs
New file
@@ -0,0 +1,137 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace ApiTools.Core.Utils.NongYePayUtils.Models
{
    [XmlRoot("ap")]
    public class NongYePayGetBalanceRequest : NongYePayBaseRequest
    {
        public NongYePayGetBalanceRequest()
        {
            TransCode = "CQRA06";
        }
        /// <summary>
        /// 业务数据
        /// </summary>
        [XmlElement("Cmp")]
        public NongYePayGetBalanceRequestCmp Cmp { get; set; }
    }
    public class NongYePayGetBalanceRequestCmp
    {
        /// <summary>
        /// 省市代码
        /// </summary>
        [XmlElement("DbProv")]
        public string ProvinceCode { get; set; }
        /// <summary>
        /// 查询账号
        /// </summary>
        [XmlElement("DbAccNo")]
        public string AccountNo { get; set; }
        /// <summary>
        /// 货币码
        /// </summary>
        [XmlElement("DbCur")]
        public string CurrencyCode { get; set; }
    }
    [XmlRoot("ap")]
    public class NongYePayGetBalanceResponse : NongYePayBaseResponse
    {
        [XmlElement("Acc")]
        public NongYePayGetBalanceResponseAcc Acc { get; set; }
        [XmlElement("Corp")]
        public NongYePayGetBalanceResponseCorp Corp { get; set; }
    }
    public class NongYePayGetBalanceResponseCorp
    {
        /// <summary>
        /// 借方户名
        /// </summary>
        [XmlElement("DbAccName")]
        public string DbAccName { get; set; }
        [XmlElement("UseState")]
        public string UseState { get; set; }
    }
    public class NongYePayGetBalanceResponseAcc
    {
        /// <summary>
        /// 账户余额
        /// </summary>
        [XmlElement("Bal")]
        public string Bal { get; set; }
        /// <summary>
        /// 账户可用余额
        /// </summary>
        [XmlElement("AvailBal")]
        public string AvailBal { get; set; }
        /// <summary>
        /// 冻结金额
        /// </summary>
        [XmlElement("FrzAmt")]
        public string FrzAmt { get; set; }
        /// <summary>
        /// 冻结余额
        /// </summary>
        [XmlElement("FrzBal")]
        public string FrzBal { get; set; }
        /// <summary>
        /// 不定期可用限额
        /// </summary>
        [XmlElement("ValUDLmt")]
        public string ValUDLmt { get; set; }
        /// <summary>
        /// 月可用限额
        /// </summary>
        [XmlElement("ValMonthLmt")]
        public string ValMonthLmt { get; set; }
        /// <summary>
        /// 日可用限额
        /// </summary>
        [XmlElement("ValDayLmt")]
        public string ValDayLmt { get; set; }
        /// <summary>
        /// 昨日可用余额
        /// </summary>
        [XmlElement("LastAvailBal")]
        public string LastAvailBal { get; set; }
        /// <summary>
        /// 昨日余额
        /// </summary>
        [XmlElement("LastBal")]
        public string LastBal { get; set; }
        /// <summary>
        /// 账户类型
        /// </summary>
        [XmlElement("AccType")]
        public string AccType { get; set; }
        /// <summary>
        /// 账户状态
        /// </summary>
        [XmlElement("AccSts")]
        public string AccSts { get; set; }
    }
}
ApiTools.Core/Utils/NongYePayUtils/NongYePayOptions.cs
New file
@@ -0,0 +1,26 @@
using Furion.ConfigurableOptions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    public class NongYePayOptions : IConfigurableOptions
    {
        /// <summary>
        /// ICT IP地址
        /// </summary>
        public string Ip { get; set; }
        /// <summary>
        /// ICP 端口
        /// </summary>
        public int Port { get; set; }
        /// <summary>
        /// 客户号
        /// </summary>
        public string CorpNo { get; set; }
    }
}
ApiTools.Core/Utils/NongYePayUtils/NongYePayUtils.cs
New file
@@ -0,0 +1,181 @@
using Aop.Api.Domain;
using ApiTools.Core.Utils.NongYePayUtils.Models;
using Furion;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DistributedIDGenerator;
using Furion.FriendlyException;
using Microsoft.Extensions.Options;
using NetTopologySuite.Algorithm;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
namespace ApiTools.Core
{
    public class NongYePayUtils(
            IOptions<NongYePayOptions> options,
            IRepository<ThreeResourceLog, LogDbContextLocator> repThreeResourceLog
        ) : ITransient
    {
        private readonly IOptions<NongYePayOptions> options = options;
        private readonly IRepository<ThreeResourceLog, LogDbContextLocator> repThreeResourceLog = repThreeResourceLog;
        /// <summary>
        /// 查询账户余额
        /// </summary>
        /// <returns>余额信息</returns>
        public Task<NongYePayGetBalanceResponse> GetBalance(NongYePayGetBalanceRequest request)
        {
            return Send<NongYePayGetBalanceRequest, NongYePayGetBalanceResponse>(request);
        }
        private async Task<TResponse> Send<TRequest, TResponse>(TRequest request)
            where TRequest : NongYePayBaseRequest
            where TResponse : NongYePayBaseResponse
        {
            var logier = JwtUtils.GetCurrentLogier();
            var now = DateTime.Now;
            var random = StringUtils.GenerateRandomString(6);
            request.CorpNo = options.Value.CorpNo;
            request.ReqDate = now.ToString("yyyyMMdd");
            request.ReqTime = now.ToString("HHmmss");
            request.ReqSeqNo = $"{now:yyyyMMddHHmmssfff}{random}";
            request.ChannelType = "ERP";
            request.ProductID = "ICC";
            string requestXml = SerializeRequest(request);
            var log = new ThreeResourceLog
            {
                CreatedTime = DateTimeOffset.Now,
                Id = IDGen.NextID(),
                TraceId = App.GetTraceId(),
                Method = EnumResourceMethod.Post,
                Domain = $"{options.Value.Ip}:{options.Value.Port}",
                Path = request.TransCode,
                CreatedUserId = logier?.Id,
                CreatedChannelId = logier?.ChannelId,
                Request = request.ToJson(),
            };
            await repThreeResourceLog.InsertNowAsync(log);
            var stopwatch = Stopwatch.StartNew();
            var responseXml = await SendRequest(requestXml);
            stopwatch.Stop();
            var response = DeserializeResponse<TResponse>(responseXml);
            log.UpdatedTime = DateTimeOffset.Now;
            log.Response = responseXml;
            log.IsSuccess = response.RespSource == "0";
            log.ElapsedMilliseconds = stopwatch.ElapsedMilliseconds;
            await repThreeResourceLog.UpdateNowAsync(log);
            if (!log.IsSuccess) throw Oops.Oh(EnumErrorCodeType.s510, $"农行接口异常:{response.RespInfo}");
            return response;
        }
        /// <summary>
        /// 泛型请求类转XML
        /// </summary>
        private string SerializeRequest<T>(T request)
        {
            var serializer = new XmlSerializer(typeof(T));
            var ns = new XmlSerializerNamespaces();
            ns.Add("", "");
            var settings = new XmlWriterSettings
            {
                OmitXmlDeclaration = true,
                Indent = false,
                Encoding = Encoding.UTF8
            };
            using var stream = new MemoryStream();
            using var writer = XmlWriter.Create(stream, settings);
            serializer.Serialize(writer, request, ns);
            // 转换为GBK编码
            stream.Position = 0;
            using var reader = new StreamReader(stream, Encoding.UTF8);
            string utf8Xml = reader.ReadToEnd();
            return Encoding.GetEncoding("GBK").GetString(Encoding.GetEncoding("GBK").GetBytes(utf8Xml));
        }
        /// <summary>
        /// XML转泛型应答类
        /// </summary>
        private T DeserializeResponse<T>(string gbkXml)
        {
            var serializer = new XmlSerializer(typeof(T));
            using var stream = new MemoryStream(Encoding.UTF8.GetBytes(gbkXml));
            return (T)serializer.Deserialize(stream);
        }
        /// <summary>
        /// 发送请求并接收应答
        /// </summary>
        private async Task<string> SendRequest(string requestXml)
        {
            byte[] requestBytes = Encoding.GetEncoding("GBK").GetBytes(requestXml);
            // 2. 构建7字节包头(加密标志0 + 数据长度,右补空格)
            byte[] header = new byte[7];
            header[0] = 0x30; // 加密标志:0(ASCII码)
            string requestLengthStr = requestBytes.Length.ToString().PadRight(6, ' '); // 后6字节:长度右补空格
            Buffer.BlockCopy(Encoding.ASCII.GetBytes(requestLengthStr), 0, header, 1, 6);
            // 3. 合并包头+数据包
            byte[] sendData = new byte[header.Length + requestBytes.Length];
            Buffer.BlockCopy(header, 0, sendData, 0, header.Length);
            Buffer.BlockCopy(requestBytes, 0, sendData, header.Length, requestBytes.Length);
            // 4. Socket发送(带超时)
            using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.SendTimeout = (int)TimeSpan.FromMinutes(5).TotalMilliseconds;
            socket.ReceiveTimeout = (int)TimeSpan.FromMinutes(5).TotalMilliseconds;
            try
            {
                await socket.ConnectAsync(options.Value.Ip, options.Value.Port);
                await socket.SendAsync(sendData);
                // 接收包头
                byte[] responseHeader = new byte[7];
                int headerLen = socket.Receive(responseHeader);
                if (headerLen != 7) throw Oops.Oh(EnumErrorCodeType.s510, "接收包头失败");
                // 解析数据长度
                string lengthStr = Encoding.ASCII.GetString(responseHeader, 1, 6).Trim();
                if (!int.TryParse(lengthStr, out int dataLength))
                    throw Oops.Oh(EnumErrorCodeType.s510, $"解析数据长度失败:{lengthStr}");
                // 接收数据包
                byte[] responseBytes = new byte[dataLength];
                int receivedLen = 0;
                while (receivedLen < dataLength)
                {
                    int len = socket.Receive(responseBytes, receivedLen, dataLength - receivedLen, SocketFlags.None);
                    receivedLen += len;
                }
                // 转换为GBK XML
                var responseXml = Encoding.GetEncoding("GBK").GetString(responseBytes);
                if (responseXml.IsNull())
                {
                    throw Oops.Oh(EnumErrorCodeType.s510, "未收到应答");
                }
                return responseXml;
            }
            finally
            {
                socket.Dispose();
            }
        }
    }
}
ApiTools.Core/Utils/StringUtils/StringUtils.cs
@@ -166,5 +166,6 @@
            }
            return result.ToString();
        }
    }
}
ApiTools.Web.Entry/Startup.cs
@@ -27,7 +27,8 @@
            services.AddConfigurableOptions<WxmpOptions>();
            services.AddConfigurableOptions<WeChatPayOptions>();
            services.AddConfigurableOptions<AlipayOptions>();
            services.AddConfigurableOptions<PingAnPayOptions>();
            services.AddConfigurableOptions<PingAnPayOptions>();
            services.AddConfigurableOptions<NongYePayOptions>();
            services.AddConfigurableOptions<ChengLiYeSmsOptions>();
            services.AddConfigurableOptions<AliyunOptions>();
            services.AddConfigurableOptions<BaiduOptions>();
ApiTools.Web.Entry/appsettings.json
@@ -96,6 +96,11 @@
  "PingAnPay": {
    "MrChCode": "0040107980000NBCS000"
  },
  "NongYePay": {
    "Ip": "183.242.60.51",
    "Port": 14028,
    "CorpNo": "14314153600000025"
  },
  "ChengLiYeSms": {
    "UserName": "nbcsxx",
    "Password": "8af9s7",