sunpengfei
8 天以前 a22af1da254b90c79fd3e1433ed98f51c0a39a65
ApiTools.Core/Utils/NongYePayUtils/NongYePayUtils.cs
@@ -1,16 +1,22 @@
using Aop.Api.Domain;
using ApiTools.Core.Utils.NongYePayUtils.Models;
using Azure;
using Azure.Core;
using Furion;
using Furion.DatabaseAccessor;
using Furion.DataEncryption.Extensions;
using Furion.DependencyInjection;
using Furion.DistributedIDGenerator;
using Furion.FriendlyException;
using Furion.HttpRemote;
using Microsoft.Extensions.Options;
using NetTopologySuite.Algorithm;
using Org.BouncyCastle.Asn1.Ocsp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Sockets;
using System.Text;
@@ -21,10 +27,12 @@
namespace ApiTools.Core
{
    public class NongYePayUtils(
            IHttpRemoteService httpRemoteService,
            IOptions<NongYePayOptions> options,
            IRepository<ThreeResourceLog, LogDbContextLocator> repThreeResourceLog
        ) : ITransient
    {
        private readonly IHttpRemoteService httpRemoteService = httpRemoteService;
        private readonly IOptions<NongYePayOptions> options = options;
        private readonly IRepository<ThreeResourceLog, LogDbContextLocator> repThreeResourceLog = repThreeResourceLog;
@@ -37,47 +45,336 @@
            return Send<NongYePayGetBalanceRequest, NongYePayGetBalanceResponse>(request);
        }
        private async Task<TResponse> Send<TRequest, TResponse>(TRequest request)
            where TRequest : NongYePayBaseRequest
            where TResponse : NongYePayBaseResponse
        /// <summary>
        /// 单笔对公转账
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public Task<NongYePaySingleCorporateTransferResponse> SingleCorporateTransfer(NongYePaySingleCorporateTransferRequest request)
        {
            var logier = JwtUtils.GetCurrentLogier();
            return Send<NongYePaySingleCorporateTransferRequest, NongYePaySingleCorporateTransferResponse>(request);
        }
        /// <summary>
        /// 查询转账状态
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public Task<NongYePayGetTransferStatusResponse> GetTransferStatus(NongYePayGetTransferStatusRequest request)
        {
            return Send<NongYePayGetTransferStatusRequest, NongYePayGetTransferStatusResponse>(request);
        }
        /// <summary>
        /// 查询转账详情
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public Task<NongYePayGetTransferDetailsResponse> GetTransferDetails(NongYePayGetTransferDetailsRequest request)
        {
            return SendWithFile<NongYePayGetTransferDetailsRequest, NongYePayGetTransferDetailsResponse, NongYePayGetTransferDetailsResponseItem>(request);
        }
        /// <summary>
        /// 获取电子回单
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public Task<NongYePayGetEreceiptsResponse> GetEreceipts(NongYePayGetEreceiptsRequest request)
        {
            return SendWithFile<NongYePayGetEreceiptsRequest, NongYePayGetEreceiptsResponse, NongYePayGetEreceiptsResponseItem>(request);
        }
        /// <summary>
        /// 下载电子回单
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<NongYePayDownloadEreceiptResponse> DownloadEreceipt(NongYePayDownloadEreceiptRequest request)
        {
            return await SendWithZip<NongYePayDownloadEreceiptRequest, NongYePayDownloadEreceiptResponse>(request);
        }
        /// <summary>
        /// 实时下载电子回单
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<NongYePayRealTimeDownloadEreceiptResponse> RealTimeDownloadEreceipt(NongYePayRealTimeDownloadEreceiptRequest request)
        {
            return await SendWithZip<NongYePayRealTimeDownloadEreceiptRequest, NongYePayRealTimeDownloadEreceiptResponse>(request);
        }
        /// <summary>
        /// 获取银行地区
        /// </summary>
        /// <returns></returns>
        public Task<List<SelectOption<string, string>>> GetBankAreas()
        {
            var list = new List<SelectOption<string, string>>
            {
                new SelectOption<string, string>("02", "天津市"),
                new SelectOption<string, string>("03", "上海"),
                new SelectOption<string, string>("04", "山西省"),
                new SelectOption<string, string>("05", "内蒙古"),
                new SelectOption<string, string>("06", "辽宁省"),
                new SelectOption<string, string>("07", "吉林省"),
                new SelectOption<string, string>("08", "黑龙江"),
                new SelectOption<string, string>("10", "江苏省"),
                new SelectOption<string, string>("11", "北京市"),
                new SelectOption<string, string>("12", "安徽省"),
                new SelectOption<string, string>("13", "福建省"),
                new SelectOption<string, string>("14", "江西省"),
                new SelectOption<string, string>("15", "山东省"),
                new SelectOption<string, string>("16", "河南省"),
                new SelectOption<string, string>("17", "湖北省"),
                new SelectOption<string, string>("18", "湖南省"),
                new SelectOption<string, string>("19", "浙江省"),
                new SelectOption<string, string>("20", "广西区"),
                new SelectOption<string, string>("21", "海南省"),
                new SelectOption<string, string>("22", "四川省"),
                new SelectOption<string, string>("23", "贵州省"),
                new SelectOption<string, string>("24", "云南省"),
                new SelectOption<string, string>("25", "西藏区"),
                new SelectOption<string, string>("26", "陕西省"),
                new SelectOption<string, string>("27", "甘肃省"),
                new SelectOption<string, string>("28", "青海省"),
                new SelectOption<string, string>("29", "宁夏区"),
                new SelectOption<string, string>("30", "新疆区"),
                new SelectOption<string, string>("31", "重庆市"),
                new SelectOption<string, string>("34", "大连市"),
                new SelectOption<string, string>("38", "青岛市"),
                new SelectOption<string, string>("39", "宁波市"),
                new SelectOption<string, string>("40", "厦门市"),
                new SelectOption<string, string>("41", "深圳市"),
                new SelectOption<string, string>("44", "广东省"),
                new SelectOption<string, string>("50", "河北省"),
                new SelectOption<string, string>("71", "台湾省"),
                new SelectOption<string, string>("81", "营业部"),
                new SelectOption<string, string>("97", "香港"),
                new SelectOption<string, string>("98", "澳门"),
                new SelectOption<string, string>("99", "总行"),
            };
            return Task.FromResult(list);
        }
        /// <summary>
        /// 获取银行
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public Task<NongYePayGetBanksResponse> GetBanks(NongYePayGetBanksRequest request)
        {
            return SendWithFile<NongYePayGetBanksRequest, NongYePayGetBanksResponse, NongYePayGetBanksResponseItem>(request);
        }
        public string GetSeqNo()
        {
            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";
            return $"{now:yyyyMMddHHmmssfff}{random}";
        }
            string requestXml = SerializeRequest(request);
            var log = new ThreeResourceLog
        private async Task<List<NongYePayResponseZipFile>> GetZipFiles(NongYePayZipResponse response)
        {
            var list = new List<NongYePayResponseZipFile>();
            if (response != null
                && response.RespSource == "0"
                && response.Cmp != null
                && response.Cmp.BatchFileName.IsNotNull())
            {
                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);
                var memoryStream = new MemoryStream();
                if (options.Value.RemoteFileUrl.IsNotNull())
                {
                    response.ZipFileName = response.Cmp.BatchFileName;
                    var url = $"{options.Value.RemoteFileUrl}/api/file/download";
                    var command = new DownloadFileCommand
                    {
                        Scene = "NongYePay",
                        Path = response.Cmp.BatchFileName
                    };
                    var timestamp = DateTime.Now.ToTimeStamp(true);
                    var sign = $"POST|/api/file/download|{command.ToJson()}|{options.Value.RemoteFilePrivateKey}|{timestamp}".ToMD5Encrypt();
                    using var stream = await httpRemoteService.PostAsStreamAsync(url,
                        builder => builder
                            .SetJsonContent(command)
                            .WithHeader("x-timestamp", timestamp, replace: true)
                            .WithHeader("x-sign", sign, replace: true));
                    stream.CopyTo(memoryStream);
                    memoryStream.Position = 0;
                }
                else if (options.Value.FilePath.IsNotNull())
                {
                    response.ZipFileName = $"{options.Value.FilePath}{response.Cmp.BatchFileName}";
                    if (File.Exists(response.ZipFileName))
                    {
                        using var stream = File.OpenRead(response.ZipFileName);
                        stream.CopyTo(memoryStream);
                        memoryStream.Position = 0;
                    }
                }
            if (!log.IsSuccess) throw Oops.Oh(EnumErrorCodeType.s510, $"农行接口异常:{response.RespInfo}");
                using (var archive = new ZipArchive(memoryStream))
                {
                    foreach (var entry in archive.Entries)
                    {
                        if (entry.FullName.EndsWith(".pdf"))
                        {
                            using (var stream = entry.Open())
                            {
                                var ms = new MemoryStream();
                                stream.CopyTo(ms);
                                ms.Position = 0;
                                list.Add(new NongYePayResponseZipFile
                                {
                                    FileName = entry.FullName,
                                    Stream = ms
                                });
                            }
                        }
                    }
                }
            }
            return list;
        }
            return response;
        private async Task<List<T>> GetList<T>(NongYePayBaseResponse<T> response, ThreeResourceLog log)
            where T : class, new()
        {
            var list = new List<T>();
            if (response.RespSource == "0"
                && response.FileFlag == "1"
                && response.Cmp.BatchFileName.IsNotNull())
            {
                var lines = new List<string>();
                if (options.Value.RemoteFileUrl.IsNotNull())
                {
                    var url = $"{options.Value.RemoteFileUrl}/api/file/download";
                    var command = new DownloadFileCommand
                    {
                        Scene = "NongYePay",
                        Path = response.Cmp.BatchFileName
                    };
                    var timestamp = DateTime.Now.ToTimeStamp(true);
                    var sign = $"POST|/api/file/download|{command.ToJson()}|{options.Value.RemoteFilePrivateKey}|{timestamp}".ToMD5Encrypt();
                    var buffer = await httpRemoteService.PostAsByteArrayAsync(url,
                       builder => builder
                           .SetJsonContent(command)
                           .WithHeader("x-timestamp", timestamp, replace: true)
                           .WithHeader("x-sign", sign, replace: true));
                    var text = Encoding.GetEncoding("GBK").GetString(buffer);
                    lines = text.Split("\n").Where(it => it.IsNotNull()).ToList();
                }
                else if (options.Value.FilePath.IsNotNull())
                {
                    var fileName = $"{options.Value.FilePath}{response.Cmp.BatchFileName}";
                    if (File.Exists(fileName))
                    {
                        var array = await File.ReadAllLinesAsync(fileName, Encoding.GetEncoding("GBK"));
                        lines = array.ToList();
                    }
                }
                if (lines.IsNotNull())
                {
                    var props = typeof(T).GetProperties();
                    foreach (var line in lines)
                    {
                        var item = new T();
                        var columns = line.Split("|");
                        for (int i = 0; i < columns.Count() - 1; i++)
                        {
                            props[i].SetValue(item, columns[i]);
                        }
                        list.Add(item);
                    }
                }
                log.UpdatedTime = DateTimeOffset.Now;
                var json = list.ToJson();
                log.Response += $"\n{json}";
                await repThreeResourceLog.UpdateNowAsync(log);
            }
            return list;
        }
        private async Task<TResponse> SendWithFile<TRequest, TResponse, TResponseItem>(TRequest request)
            where TRequest : NongYePayBaseRequest
            where TResponse : NongYePayBaseResponse<TResponseItem>, new()
            where TResponseItem : class, new()
        {
            var response = await SendWithLog<TRequest, TResponse>(request);
            response.response.Items = await GetList(response.response, response.log);
            return response.response;
        }
        private async Task<TResponse> SendWithZip<TRequest, TResponse>(TRequest request)
            where TRequest : NongYePayBaseRequest
            where TResponse : NongYePayZipResponse, new()
        {
            var response = await SendWithLog<TRequest, TResponse>(request);
            response.response.Items = await GetZipFiles(response.response);
            return response.response;
        }
        private async Task<TResponse> Send<TRequest, TResponse>(TRequest request)
            where TRequest : NongYePayBaseRequest
            where TResponse : NongYePayBaseResponse, new()
        {
            var response = await SendWithLog<TRequest, TResponse>(request);
            return response.response;
        }
        private async Task<(TResponse response, ThreeResourceLog log)> SendWithLog<TRequest, TResponse>(TRequest request)
            where TRequest : NongYePayBaseRequest
            where TResponse : NongYePayBaseResponse, new()
        {
            try
            {
                var logier = JwtUtils.GetCurrentLogier();
                var now = DateTime.Now;
                request.CorpNo = options.Value.CorpNo;
                request.OpNo = options.Value.OpNo;
                request.AuthNo = "";
                request.Sign = "";
                request.ReqDate = now.ToString("yyyyMMdd");
                request.ReqTime = now.ToString("HHmmss");
                request.ReqSeqNo = request.ReqSeqNo ?? GetSeqNo();
                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.CCTransCode,
                    CreatedUserId = logier?.Id,
                    CreatedChannelId = logier?.ChannelId,
                    Request = requestXml,
                };
                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);
                return (response, log);
            }
            catch (Exception ex)
            {
                return (new TResponse
                {
                    RespSource = "500",
                    RespInfo = ex.Message
                }, null);
            }
        }
        /// <summary>
@@ -112,9 +409,12 @@
        /// </summary>
        private T DeserializeResponse<T>(string gbkXml)
        {
            var buffer = Encoding.GetEncoding("GBK").GetBytes(gbkXml);
            using var ms = new MemoryStream(buffer);
            using var sr = new StreamReader(ms, Encoding.GetEncoding("GBK"));
            var serializer = new XmlSerializer(typeof(T));
            using var stream = new MemoryStream(Encoding.UTF8.GetBytes(gbkXml));
            return (T)serializer.Deserialize(stream);
            using var xr = XmlReader.Create(sr);
            return (T)serializer.Deserialize(xr);
        }
        /// <summary>