From bda2679db0d10a0328a71ff4f55f000d26ef10dc Mon Sep 17 00:00:00 2001 From: zhengyuxuan <zhengyuxuan1995> Date: 星期五, 21 三月 2025 14:51:32 +0800 Subject: [PATCH] fix:bug修复 --- LifePayment/LifePayment.Application/LifePay/LifePayService.cs | 1234 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 1,172 insertions(+), 62 deletions(-) diff --git a/LifePayment/LifePayment.Application/LifePay/LifePayService.cs b/LifePayment/LifePayment.Application/LifePay/LifePayService.cs index 8f950fe..e24db15 100644 --- a/LifePayment/LifePayment.Application/LifePay/LifePayService.cs +++ b/LifePayment/LifePayment.Application/LifePay/LifePayService.cs @@ -1,31 +1,31 @@ -锘縰sing DynamicQuery.Net.Dto.Input; -using LifePayment.Application.Contracts; +锘縰sing LifePayment.Application.Contracts; using LifePayment.Domain; +using LifePayment.Domain.LifePay; using LifePayment.Domain.Models; using LifePayment.Domain.Shared; -using MailKit.Search; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Nest; using Newtonsoft.Json; -using NPOI.OpenXmlFormats.Dml.Chart; -using NPOI.SS.Formula.Functions; -using StackExchange.Redis; using System; using System.Collections.Generic; using System.Linq; -using System.Security.Cryptography; +using System.Linq.Dynamic.Core; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Application.Services; -using Volo.Abp.Domain.Entities; +using Volo.Abp.Data; using Volo.Abp.Domain.Repositories; using Volo.Abp.EventBus.Distributed; +using Z.EntityFramework.Plus; using ZeroD.Util; -using ZeroD.Util.Fadd; +using Alipay.EasySDK.Payment.Common.Models; using static LifePayment.Domain.Shared.LifePaymentConstant; -using static IdentityServer4.Models.IdentityResources; +using ZeroD.Util.Fadd; +using Nest; +using Volo.Abp.Domain.Entities; +using Volo.Abp.ObjectMapping; +using NPOI.SS.Formula.Functions; namespace LifePayment.Application; @@ -35,10 +35,18 @@ private readonly ILogger<LifePayService> _logger; private readonly IRepository<LifePayRate, Guid> _lifePayRateRepository; + private readonly IRepository<LifePayPremium, Guid> _lifePayPremiumRepository; private readonly IRepository<LifePayOrder, Guid> _lifePayOrderRepository; private readonly IRepository<LifePayUser, Guid> _lifePayUserRepository; - + private readonly IRepository<LifePayIntroInfo, Guid> _lifePayIntroInfoRepository; + private readonly IRepository<DallyStatistics, Guid> _dallyStatisticsRepository; + private readonly IRepository<LifePayChannles, Guid> _lifePayChannlesRep; + private readonly IRepository<LifePayAccount, Guid> _lifePayAccount; + private readonly IRepository<OperateHistory, Guid> _operateHistory; + private readonly IDataFilter dataFilter; + private readonly IChannelFilter _channelFilter; private readonly IAliPayApi _aliPayApi; + private readonly IAlipayInterfaceManager _alipayInterfaceManager; private readonly IWxPayApi _wxPayApi; private readonly WxPayOption _wxPayOptions; @@ -50,22 +58,79 @@ IRepository<LifePayRate, Guid> lifePayRateRepository, IRepository<LifePayOrder, Guid> lifePayOrderRepository, IRepository<LifePayUser, Guid> lifePayUserRepository, + IRepository<LifePayPremium, Guid> lifePayPremiumRepository, + IRepository<LifePayIntroInfo, Guid> lifePayIntroInfoRepository, + IRepository<DallyStatistics, Guid> dallyStatisticsRepository, + IRepository<OperateHistory, Guid> operateHistory, IAliPayApi aliPayApi, + IAlipayInterfaceManager aliPayInterfaceManager, IWxPayApi wxPayApi, - IOptions<WxPayOption> wxPayOptions) + IOptions<WxPayOption> wxPayOptions, + IRepository<LifePayChannles, Guid> lifePayChannlesRep, + IRepository<LifePayAccount, Guid> lifePayAccount, + IDataFilter dataFilter, + IChannelFilter channelFilter) { _logger = logger; _aCOOLYManager = aCOOLYManager; _lifePayRateRepository = lifePayRateRepository; _lifePayOrderRepository = lifePayOrderRepository; _lifePayUserRepository = lifePayUserRepository; + _lifePayPremiumRepository = lifePayPremiumRepository; + _lifePayIntroInfoRepository = lifePayIntroInfoRepository; + _dallyStatisticsRepository = dallyStatisticsRepository; _aliPayApi = aliPayApi; + _alipayInterfaceManager = aliPayInterfaceManager; _wxPayApi = wxPayApi; _wxPayOptions = wxPayOptions.Value; _distributedEventBus = distributedEventBus; + _lifePayChannlesRep = lifePayChannlesRep; + _lifePayAccount = lifePayAccount; + this.dataFilter = dataFilter; + _channelFilter = channelFilter; + _operateHistory = operateHistory; } #region 鏌ヨ + + public async Task<TopStatisticsOutput> GetTopStatistics() + { + var today = DateTime.Now.Date; + var statistics = await _dallyStatisticsRepository.Where(x => x.CreationTime.Date == today).FirstOrDefaultAsync(); + if (statistics == null) + { + var accumulatedReceipts = await _lifePayOrderRepository.Where(x => x.CreationTime < today).SumAsync(x => x.PayAmount); + var receiptsYesterday = await _lifePayOrderRepository.Where(x => x.CreationTime >= today.AddDays(-1) && x.CreationTime < today).SumAsync(x => x.PayAmount); + var accumulatedOrders = await _lifePayOrderRepository.Where(x => x.CreationTime < today).CountAsync(); + var accumulatedIncome = await _lifePayOrderRepository.Where(x => x.CreationTime < today).SumAsync(x => x.ActualRechargeAmount); + var ordersNumYesterday = await _lifePayOrderRepository.Where(x => x.CreationTime >= today.AddDays(-1) && x.CreationTime < today).CountAsync(); + var yesterdaySuccess = await _lifePayOrderRepository.Where(x => x.CreationTime >= today.AddDays(-1) && x.CreationTime < today && x.LifePayOrderStatus == LifePayOrderStatusEnum.宸插畬鎴�).CountAsync(); + var yesterdayFail = await _lifePayOrderRepository.Where(x => x.CreationTime >= today.AddDays(-1) && x.CreationTime < today && x.LifePayOrderStatus == LifePayOrderStatusEnum.宸插け璐�).CountAsync(); + var accumulatedUsers = await _lifePayUserRepository.CountAsync(); + + var entity = new DallyStatistics() + { + Id = GuidGenerator.Create(), + CreationTime = DateTime.Now, + Amount = 0, + AccumulatedReceipts = accumulatedReceipts, + ReceiptsYesterday = receiptsYesterday, + AccumulatedOrders = accumulatedOrders, + OrdersNumYesterday = ordersNumYesterday, + YesterdaySuccess = yesterdaySuccess, + YesterdayFail = yesterdayFail, + AccumulatedUsers = accumulatedUsers, + }; + await _dallyStatisticsRepository.InsertAsync(entity); + //var result = ObjectMapper.Map<DallyStatistics, TopStatisticsOutput>(entity); + return new TopStatisticsOutput(); + } + else + { + var result = ObjectMapper.Map<DallyStatistics, TopStatisticsOutput>(statistics); + return result; + } + } /// <summary> /// 鑾峰彇鐢佃垂闈㈠�� @@ -97,12 +162,52 @@ } /// <summary> + /// 鑾峰彇璇濊垂闈㈠�� + /// </summary> + /// <param name="input"></param> + /// <returns></returns> + public async Task<GasParValueResponse> GetGasParValue() + { + return await _aCOOLYManager.GasParValue(new GasParValueRequestInput()); + } + + /// <summary> + /// 鑾峰彇鐕冩皵鏀寔鍟嗘埛 + /// </summary> + /// <returns></returns> + public async Task<GasOrgTypeValueResponse> GetGasOrgType() + { + return await _aCOOLYManager.GasOrgType(new GasOrgTypeRequestInput()); + } + + /// <summary> /// 鑾峰彇鎶樻墸 /// </summary> /// <returns></returns> public async Task<List<LifePayRateListOutput>> GetRate() { - return await _lifePayRateRepository.Select(x => new LifePayRateListOutput() { Rate = x.Rate, RateType = x.RateType }) + return await _lifePayRateRepository.Where(x => x.IsDeleted == false).Select(x => new LifePayRateListOutput() { Id = x.Id, Rate = x.Rate, RateType = x.RateType }) + .ToListAsync(); + } + + /// <summary> + /// 鑾峰彇鎵嬬画璐硅垂鐜� + /// </summary> + /// <returns></returns> + public async Task<List<LifePayPremiumListOutput>> GetPremium() + { + return await _lifePayPremiumRepository.Where(x => x.IsDeleted == false).Select(x => new LifePayPremiumListOutput() { Id = x.Id, Rate = x.Rate, PremiumType = x.PremiumType }) + .ToListAsync(); + } + + /// <summary> + /// 椤荤煡閰嶇疆 + /// </summary> + /// <returns></returns> + public async Task<List<LifePayIntroInfoOutput>> GetIntroInfo(LifePayOrderTypeEnum lifePayType) + { + return await _lifePayIntroInfoRepository.Where(x => x.IsDeleted == false && x.LifePayType == lifePayType).OrderBy(x => x.Sequence) + .Select(x => new LifePayIntroInfoOutput() { Type = x.Type, ContentSummary = x.ContentSummary, Content = x.Content, LifePayType = x.LifePayType, Path = x.Path, Sequence = x.Sequence }) .ToListAsync(); } @@ -111,17 +216,54 @@ /// </summary> /// <param name="input"></param> /// <returns></returns> - public async Task<PageOutput<UserListOutput>> GetUserPage(PageInput input) + public async Task<PageOutput<UserListOutput>> GetUserPage(QueryUserPageInput input) { - return await _lifePayUserRepository.Select(x => + return await _channelFilter.GetChannelLifePayUserFilter(_lifePayUserRepository).Where(x => x.IsDeleted == false) + .WhereIf(!string.IsNullOrEmpty(input.QueryCondition), x => x.PhoneNumber.Contains(input.QueryCondition) || x.Name.Contains(input.QueryCondition)) + .WhereIf(input.CreationTimeBegin.HasValue, x => x.CreationTime >= input.CreationTimeBegin) + .WhereIf(input.CreationTimeEnd.HasValue, x => x.CreationTime <= input.CreationTimeEnd) + .Select(x => new UserListOutput() { Id = x.Id, + CreationChannle = string.IsNullOrEmpty(x.CreationChannleNum) ? "" : _lifePayChannlesRep.Where(c => c.ChannlesNum == x.CreationChannleNum).FirstOrDefault().ChannlesName, + LastLoginChannle = string.IsNullOrEmpty(x.LastLoginChannleNum) ? "" : _lifePayChannlesRep.Where(c => c.ChannlesNum == x.LastLoginChannleNum).FirstOrDefault().ChannlesName, PhoneNumber = x.PhoneNumber, + Name = string.IsNullOrEmpty(x.Name) ? "" : x.Name, CreationTime = x.CreationTime, LastLoginTime = x.LastLoginTime }) .GetPageResult(input.PageModel); + } + + /// <summary> + /// 鑾峰彇鐢ㄦ埛鎴峰彿鍒嗛〉鏁版嵁 + /// </summary> + /// <param name="input"></param> + /// <returns></returns> + public async Task<PageOutput<UserAccountOutput>> GetAccountPage(QueryUserAccountListInput input) + { + using (dataFilter.Disable<ISoftDelete>()) + { + return await _lifePayAccount.Where(x => x.UserId == input.UserId) + .WhereIf(input.LifePayOrderType.HasValue, x => x.LifePayType == input.LifePayOrderType) + .OrderByDescending(x => x.CreationTime) + .Select(x => + new UserAccountOutput + { + Id = x.Id, + LifePayType = x.LifePayType, + Content = x.Content, + CreationTime = x.CreationTime, + Remark = x.Remark, + Operators = x.Operators, + Province = x.Province, + City = x.City, + ExtraProperties = x.ExtraProperties, + IsDeleted = x.IsDeleted + }) + .GetPageResult(input.PageModel); + } } /// <summary> @@ -131,36 +273,207 @@ /// <returns></returns> public async Task<PageOutput<LifePayOrderListOutput>> GetLifePayOrderPage(QueryLifePayOrderListInput input) { - return await _lifePayOrderRepository.Where(x => x.PayStatus != LifePayStatusEnum.鏈敮浠�) - .WhereIf(input.BeginFinishTime.HasValue, x => x.FinishTime >= input.BeginFinishTime) + var result = await (from a in _channelFilter.GetChannelLifePayOrderFilter(_lifePayOrderRepository) + .WhereIf(input.BeginFinishTime.HasValue, x => x.FinishTime >= input.BeginFinishTime) .WhereIf(input.EndFinishTime.HasValue, x => x.FinishTime <= input.EndFinishTime) .WhereIf(input.BeginPayTime.HasValue, x => x.PayTime >= input.BeginPayTime) + .WhereIf(input.LifePayType.HasValue, x => x.LifePayType == input.LifePayType) .WhereIf(input.EndPayTime.HasValue, x => x.PayTime <= input.EndPayTime) .WhereIf(input.LifePayOrderStatus.HasValue, x => x.LifePayOrderStatus == input.LifePayOrderStatus.Value) .WhereIf(input.PayStatus.HasValue, x => x.PayStatus == input.PayStatus.Value) + .WhereIf(input.ACOOLYStatus.HasValue, x => x.ACOOLYStatus == input.ACOOLYStatus.Value) .WhereIf(input.LifePayOrderType.HasValue, x => x.LifePayOrderType == input.LifePayOrderType.Value) .WhereIf(input.UserId.HasValue, x => x.UserId == input.UserId.Value) - .Select(x => - new LifePayOrderListOutput - { - DiscountAmount = x.DiscountAmount, - FinishTime = x.FinishTime, - Id = x.Id, - LifePayOrderStatus = x.LifePayOrderStatus, - LifePayOrderType = x.LifePayOrderType, - LifePayType = x.LifePayType, - OrderNo = x.OrderNo, - PayAmount = x.PayAmount, - PhoneNumber = x.PhoneNumber, - RechargeAmount = x.RechargeAmount, - UserId = x.UserId, - OutOrderNo = x.OutOrderNo, - PayStatus = x.PayStatus, - PayTime = x.PayTime, - RefundCredentialsImgUrl = x.RefundCredentialsImgUrl, - CreationTime = x.CreationTime - }) - .GetPageResult(input.PageModel); + .WhereIf(input.KeyWords.IsNotNullOrEmpty(), x => x.PhoneNumber.Contains(input.KeyWords) || x.OrderNo.Contains(input.KeyWords) || x.OutOrderNo.Contains(input.KeyWords) || x.ACOOLYOrderNo.Contains(input.KeyWords)) + join b in _lifePayChannlesRep on a.ChannelId equals b.ChannlesNum into temp + from b in temp.DefaultIfEmpty() + select new LifePayOrderListOutput + { + DiscountAmount = a.DiscountAmount, + FinishTime = a.FinishTime, + Id = a.Id, + LifePayOrderStatus = a.LifePayOrderStatus, + LifePayOrderType = a.LifePayOrderType, + LifePayType = a.LifePayType, + OrderNo = a.OrderNo, + PayAmount = a.PayAmount, + PhoneNumber = a.PhoneNumber, + RechargeAmount = a.RechargeAmount, + UserId = a.UserId, + OutOrderNo = a.OutOrderNo, + PayStatus = a.PayStatus, + PayTime = a.PayTime, + ACOOLYOrderNo = a.ACOOLYOrderNo, + RefundCredentialsImgUrl = a.RefundCredentialsImgUrl.GetOssPath(), + RefundPrice = a.RefundPrice, + CreationTime = a.CreationTime, + RefundCheckRemark = a.RefundCheckRemark, + RefundApplyRemark = a.RefundApplyRemark, + RefundTime = a.RefundTime, + ChannelName = b.ChannlesName, + ActualRechargeAmount = a.ActualRechargeAmount, + PlatformDeductionAmount = a.PlatformDeductionAmount, + ACOOLYStatus = a.ACOOLYStatus, + LifePayRefundStatus = a.LifePayRefundStatus, + }).GetPageResult(input.PageModel); + + return result; + } + + /// <summary> + /// 閫�娆捐鍗曞垎椤� + /// </summary> + /// <param name="input"></param> + /// <returns></returns> + public async Task<PageOutput<LifePayOrderListOutput>> GetLifePayRefundOrderPage(QueryLifePayRefundOrderListInput input) + { + + var result = await (from a in _channelFilter.GetChannelLifePayOrderFilter(_lifePayOrderRepository) + .Where(x => x.PayStatus == LifePayStatusEnum.寰呴��娆� || x.PayStatus == LifePayStatusEnum.宸查��娆� || x.PayStatus == LifePayStatusEnum.閫�娆句腑 + || x.LifePayOrderStatus == LifePayOrderStatusEnum.閫�娆惧緟瀹℃牳 || x.LifePayOrderStatus == LifePayOrderStatusEnum.宸查��娆� || x.LifePayOrderStatus == LifePayOrderStatusEnum.閫�娆惧け璐� + || x.LifePayRefundStatus > LifePayRefundStatusEnum.鏃犻渶閫�娆�) + .WhereIf(input.BeginFinishTime.HasValue, x => x.FinishTime >= input.BeginFinishTime) + .WhereIf(input.EndFinishTime.HasValue, x => x.FinishTime <= input.EndFinishTime) + .WhereIf(input.BeginRefundApplyTime.HasValue, x => x.RefundApplyTime >= input.BeginRefundApplyTime) + .WhereIf(input.LifePayType.HasValue, x => x.LifePayType == input.LifePayType) + .WhereIf(input.EndRefundApplyTime.HasValue, x => x.RefundApplyTime <= input.EndRefundApplyTime) + .WhereIf(input.LifePayOrderStatus.HasValue, x => x.LifePayOrderStatus == input.LifePayOrderStatus.Value) + .WhereIf(input.ACOOLYStatus.HasValue, x => x.ACOOLYStatus == input.ACOOLYStatus.Value) + .WhereIf(input.LifePayOrderType.HasValue, x => x.LifePayOrderType == input.LifePayOrderType.Value) + .WhereIf(input.UserId.HasValue, x => x.UserId == input.UserId.Value) + .WhereIf(input.KeyWords.IsNotNullOrEmpty(), x => x.PhoneNumber.Contains(input.KeyWords) || x.OrderNo.Contains(input.KeyWords) || x.OutOrderNo.Contains(input.KeyWords) || x.ACOOLYOrderNo.Contains(input.KeyWords)) + join b in _lifePayChannlesRep on a.ChannelId equals b.ChannlesNum into temp + from b in temp.DefaultIfEmpty() + select new LifePayOrderListOutput + { + DiscountAmount = a.DiscountAmount, + FinishTime = a.FinishTime, + Id = a.Id, + LifePayOrderStatus = a.LifePayOrderStatus, + LifePayOrderType = a.LifePayOrderType, + LifePayType = a.LifePayType, + OrderNo = a.OrderNo, + PayAmount = a.PayAmount, + PhoneNumber = a.PhoneNumber, + RechargeAmount = a.RechargeAmount, + UserId = a.UserId, + OutOrderNo = a.OutOrderNo, + PayStatus = a.PayStatus, + PayTime = a.PayTime, + ACOOLYOrderNo = a.ACOOLYOrderNo, + RefundCredentialsImgUrl = a.RefundCredentialsImgUrl.GetOssPath(), + CreationTime = a.CreationTime, + RefundCheckRemark = a.RefundCheckRemark, + RefundApplyRemark = a.RefundApplyRemark, + RefundApplyTime = a.RefundApplyTime, + RefundTime = a.RefundTime, + RefundPrice = a.RefundPrice, + ChannelName = b.ChannlesName, + ActualRechargeAmount = a.ActualRechargeAmount, + PlatformDeductionAmount = a.PlatformDeductionAmount, + ACOOLYStatus = a.ACOOLYStatus, + LifePayRefundStatus = a.LifePayRefundStatus, + }).GetPageResult(input.PageModel); + + return result; + } + + public async Task<LifePayOrderOutput> GetLifePayOrderDetail(string orderNo) + { + var order = await _lifePayOrderRepository.Where(x => x.OrderNo == orderNo).FirstOrDefaultAsync(); + var platformRate = await _lifePayRateRepository.FirstOrDefaultAsync(r => r.RateType == LifePayRateTypeEnum.渚涘簲鍟嗘姌鎵d环); + var channle = await _lifePayChannlesRep.FirstOrDefaultAsync(r => r.ChannlesNum == order.ChannelId); + var premium = await _lifePayPremiumRepository.Where(x => x.IsDeleted == false && x.PremiumType == order.LifePayType).FirstOrDefaultAsync(); + CheckExtensions.IfTrueThrowUserFriendlyException(order == null, "璁㈠崟涓嶅瓨鍦�"); + var user = await _lifePayUserRepository.FirstOrDefaultAsync(x => x.Id == order.UserId); + + var channlesRakePrice = (order.PayAmount - (order.PlatformDeductionAmount == null ? 0 : order.PlatformDeductionAmount)) * channle.ChannlesRakeRate / 100; + var result = new LifePayOrderOutput() + { + UserName = user.Name, + UserPhoneNumber = user.PhoneNumber, + DiscountAmount = order.DiscountAmount, + FinishTime = order.FinishTime, + Id = order.Id, + OutOrderNo = order.OutOrderNo, + LifePayChannle = channle.ChannlesName, + Status = order.LifePayOrderStatus, + LifePayOrderType = order.LifePayOrderType, + LifePayType = order.LifePayType, + OrderNo = order.OrderNo, + PayAmount = order.PayAmount, + RechargeAmount = order.RechargeAmount, + PayStatus = order.PayStatus, + PayTime = order.PayTime, + OrderParamDetailJsonStr = order.OrderParamDetailJsonStr, + RefundCredentialsImgUrl = order.RefundCredentialsImgUrl.GetOssPath(), + CreationTime = order.CreationTime, + RefundCheckRemark = order.RefundCheckRemark, + RefundApplyRemark = order.RefundApplyRemark, + RefundTime = order.RefundTime, + ACOOLYOrderNo = order.ACOOLYOrderNo, + LifePayRefundStatus = order.LifePayRefundStatus, + ActualRechargeAmount = order.ActualRechargeAmount, + RefundPrice = order.RefundPrice, + PlatformRate = platformRate.Rate, + PlatformPrice = order.PlatformDeductionAmount, + ElecBillUrl = order.ElecBillUrl.GetOssPath(), + RefundElecBillUrl = order.RefundElecBillUrl.GetOssPath(), + ChannleRate = channle.ChannlesRate, + ChannlesRakeRate = channle.ChannlesRakeRate, + ChannlesRakePrice = channlesRakePrice.HasValue ? 0 : Math.Round(channlesRakePrice.Value, 2), + PremiumRate = premium == null ? 0 : premium.Rate, + PremiumPrice = premium == null ? 0 : Math.Round(order.PayAmount * premium.Rate, 2), + Profit = (order.PayAmount - order.PlatformDeductionAmount) * (1.00m - channle.ChannlesRakeRate / 100) - (premium == null ? 0 : Math.Round(order.PayAmount * premium.Rate, 2)) + }; + + return result; + } + + public async Task<LifePayRefundOrderOutput> GetLifePayRefundOrderDetail(string orderNo) + { + var order = await _lifePayOrderRepository.Where(x => x.OrderNo == orderNo).FirstOrDefaultAsync(); + var platformRate = await _lifePayRateRepository.FirstOrDefaultAsync(r => r.RateType == LifePayRateTypeEnum.渚涘簲鍟嗘姌鎵d环); + var channle = await _lifePayChannlesRep.FirstOrDefaultAsync(r => r.ChannlesNum == order.ChannelId); + var premium = await _lifePayPremiumRepository.Where(x => x.IsDeleted == false && x.PremiumType == order.LifePayType).FirstOrDefaultAsync(); + CheckExtensions.IfTrueThrowUserFriendlyException(order == null, "璁㈠崟涓嶅瓨鍦�"); + var user = await _lifePayUserRepository.FirstOrDefaultAsync(x => x.Id == order.UserId); + + var channlesRakePrice = (order.PayAmount - (order.PlatformDeductionAmount == null ? 0 : order.PlatformDeductionAmount)) * channle.ChannlesRakeRate / 100; + var result = new LifePayRefundOrderOutput() + { + UserName = user.Name, + UserPhoneNumber = user.PhoneNumber, + DiscountAmount = order.DiscountAmount, + FinishTime = order.FinishTime, + Id = order.Id, + OutOrderNo = order.OutOrderNo, + LifePayChannle = channle.ChannlesName, + Status = order.LifePayOrderStatus, + LifePayOrderType = order.LifePayOrderType, + LifePayType = order.LifePayType, + OrderNo = order.OrderNo, + PayAmount = order.PayAmount, + RechargeAmount = order.RechargeAmount, + PayStatus = order.PayStatus, + PayTime = order.PayTime, + RefundCredentialsImgUrl = order.RefundCredentialsImgUrl.GetOssPath(), + CreationTime = order.CreationTime, + RefundCheckRemark = order.RefundCheckRemark, + RefundApplyRemark = order.RefundApplyRemark, + RefundApplyTime = order.RefundApplyTime, + RefundTime = order.RefundTime, + RefundOrderNo = order.RefundOrderNo, + ACOOLYOrderNo = order.ACOOLYOrderNo, + LifePayRefundStatus = order.LifePayRefundStatus, + ActualRechargeAmount = order.ActualRechargeAmount, + ActualReceivedAmount = order.ActualReceivedAmount, + RefundPrice = order.RefundPrice, + ElecBillUrl = order.ElecBillUrl.GetOssPath(), + RefundElecBillUrl = order.RefundElecBillUrl.GetOssPath(), + }; + + return result; } /// <summary> @@ -175,7 +488,7 @@ return new PageOutput<UserLifePayOrderOutput>(); } - return await _lifePayOrderRepository.Where(x => x.PayStatus != LifePayStatusEnum.鏈敮浠�) + return await _channelFilter.GetChannelLifePayOrderFilter(_lifePayOrderRepository).Where(x => x.PayStatus != LifePayStatusEnum.鏈敮浠�) .WhereIf(input.BeginFinishTime.HasValue, x => x.FinishTime >= input.BeginFinishTime) .WhereIf(input.EndFinishTime.HasValue, x => x.FinishTime <= input.EndFinishTime) .WhereIf(input.BeginPayTime.HasValue, x => x.PayTime >= input.BeginPayTime) @@ -199,11 +512,48 @@ PayStatus = x.PayStatus, PayTime = x.PayTime, OrderParamDetailJsonStr = x.OrderParamDetailJsonStr, + RefundCredentialsImgUrl = x.RefundCredentialsImgUrl.GetOssPath(), CreationTime = x.CreationTime, - RefundTime = x.RefundTime + RefundCheckRemark = x.RefundCheckRemark, + RefundApplyRemark = x.RefundApplyRemark, + RefundTime = x.RefundTime, + ACOOLYOrderNo = x.ACOOLYOrderNo, }) .GetPageResult(input.PageModel); } + + public async Task<UserLifePayOrderOutput> GetUserLifePayOrderDetail(string orderNo) + { + var result = await _lifePayOrderRepository.Where(x => x.OrderNo == orderNo) + .Select(x => + new UserLifePayOrderOutput + { + DiscountAmount = x.DiscountAmount, + FinishTime = x.FinishTime, + Id = x.Id, + LifePayOrderStatus = x.LifePayOrderStatus, + LifePayOrderType = x.LifePayOrderType, + LifePayType = x.LifePayType, + OrderNo = x.OrderNo, + PayAmount = x.PayAmount, + RechargeAmount = x.RechargeAmount, + PayStatus = x.PayStatus, + PayTime = x.PayTime, + OrderParamDetailJsonStr = x.OrderParamDetailJsonStr, + RefundCredentialsImgUrl = x.RefundCredentialsImgUrl.GetOssPath(), + CreationTime = x.CreationTime, + RefundCheckRemark = x.RefundCheckRemark, + RefundApplyRemark = x.RefundApplyRemark, + RefundTime = x.RefundTime, + ACOOLYOrderNo = x.ACOOLYOrderNo, + }) + .FirstOrDefaultAsync(); + CheckExtensions.IfTrueThrowUserFriendlyException(result == null, "璁㈠崟涓嶅瓨鍦�"); + + return result; + } + + /// <summary> /// 鏍规嵁璁㈠崟鍙疯幏鍙栨敮浠樼姸鎬� @@ -217,6 +567,226 @@ .FirstOrDefaultAsync(); } + public async Task<PageOutput<CreateEditPayChannelsInput>> GetLifePayChannlesPage(PageInput input) + { + return await GetLifePayChannlesListFilter().GetPageResult(input.PageModel); + } + + public async Task<List<CreateEditPayChannelsInput>> GetLifePayChannlesAllList() + { + return await GetLifePayChannlesListFilter().Where(x => x.Status == LifePayChannelsStatsEnum.鍚敤).ToListAsync(); + } + + public async Task<CreateEditPayChannelsInput> GetLifePayChannlesDto(Guid id) + { + return await _lifePayChannlesRep.Where(x => x.Id == id).Select(x => + new CreateEditPayChannelsInput + { + Id = x.Id, + ChannlesRate = x.ChannlesRate, + ChannlesRakeRate = x.ChannlesRakeRate, + ChannlesName = x.ChannlesName, + ChannlesNum = x.ChannlesNum, + Status = x.Status, + SwitchType = x.SwitchType, + ChannlesType = x.ChannlesType, + }).FirstOrDefaultAsync(); + } + + public async Task<CreateEditPayChannelsInput> GetLifePayChannlesDtoByNum(string channlesNum) + { + var result = await _lifePayChannlesRep.Where(x => x.ChannlesNum == channlesNum && x.Status == LifePayChannelsStatsEnum.鍚敤).Select(x => + new CreateEditPayChannelsInput + { + Id = x.Id, + ChannlesRate = x.ChannlesRate, + ChannlesRakeRate = x.ChannlesRakeRate, + ChannlesName = x.ChannlesName, + ChannlesNum = x.ChannlesNum, + Status = x.Status, + SwitchType = x.SwitchType, + ChannlesType = x.ChannlesType, + }).FirstOrDefaultAsync(); + return result; + } + + public async Task<UserLifePayOrderRefundOutput> GetUserLifePayOrderRefund(Guid id) + { + var order = await _channelFilter.GetChannelLifePayOrderFilter(_lifePayOrderRepository).Where(x => x.Id == id).Select(x => + new UserLifePayOrderRefundOutput + { + Id = x.Id, + OrderNo = x.OrderNo, + RefundCheckRemark = x.RefundCheckRemark, + RefundApplyRemark = x.RefundApplyRemark, + LifePayOrderStatus = x.LifePayOrderStatus, + }).FirstOrDefaultAsync(); + + CheckExtensions.IfTrueThrowUserFriendlyException(order == null, "鏈壘鍒拌鍗曚俊鎭�"); + + return order; + } + + public async Task<PageOutput<UserAccountOutput>> GetUserAccountList(QueryUserAccountListInput input) + { + if (!input.UserId.HasValue) + { + return new PageOutput<UserAccountOutput>(); + } + + var result = await _lifePayAccount.Where(x => x.UserId == input.UserId && x.IsDeleted == false) + .WhereIf(input.LifePayOrderType.HasValue, x => x.LifePayType == input.LifePayOrderType) + .OrderByDescending(x => x.CreationTime) + .Select(x => + new UserAccountOutput + { + Id = x.Id, + LifePayType = x.LifePayType, + Content = x.Content, + CreationTime = x.CreationTime, + Remark = x.Remark, + Operators = x.Operators, + Province = x.Province, + City = x.City, + ExtraProperties = x.ExtraProperties, + }) + .GetPageResult(input.PageModel); + return result; + } + + public async Task<List<UserAccountOutput>> GetUserAccountAllList(QueryUserAccountAllListInput input) + { + if (!input.UserId.HasValue) + { + return new List<UserAccountOutput>(); + } + + var result = await _lifePayAccount.Where(x => x.UserId == input.UserId && x.IsDeleted == false) + .WhereIf(input.LifePayOrderType.HasValue, x => x.LifePayType == input.LifePayOrderType) + .OrderByDescending(x => x.CreationTime) + .Select(x => + new UserAccountOutput + { + Id = x.Id, + LifePayType = x.LifePayType, + Content = x.Content, + CreationTime = x.CreationTime, + Remark = x.Remark, + Operators = x.Operators, + Province = x.Province, + City = x.City, + ExtraProperties = x.ExtraProperties, + }).ToListAsync(); + return result; + } + + public async Task<UserAccountOutput> GetUserAccountDetail(Guid id) + { + var result = await _lifePayAccount.Where(x => x.Id == id) + .OrderByDescending(x => x.CreationTime) + .Select(x => + new UserAccountOutput + { + Id = x.Id, + LifePayType = x.LifePayType, + Content = x.Content, + CreationTime = x.CreationTime, + Remark = x.Remark, + Operators = x.Operators, + Province = x.Province, + City = x.City, + ExtraProperties = x.ExtraProperties, + }).FirstOrDefaultAsync(); + + CheckExtensions.IfTrueThrowUserFriendlyException(result == null, "鏈壘鍒版埛鍙蜂俊鎭�"); + return result; + } + + public async Task<List<LifePayOrderListTemplate>> GetLifePayOrderPageExport(QueryLifePayOrderListInput input) + { + var result = await (await GetLifePayOrderListFilter(input)).Select(x => new LifePayOrderListTemplate + { + DiscountAmount = x.DiscountAmount, + FinishTime = x.FinishTime, + LifePayOrderStatus = x.LifePayOrderStatus, + LifePayOrderType = x.LifePayOrderType, + LifePayType = x.LifePayType, + OrderNo = x.OrderNo, + PayAmount = x.PayAmount, + PhoneNumber = x.PhoneNumber, + RechargeAmount = x.RechargeAmount, + OutOrderNo = x.OutOrderNo, + PayStatus = x.PayStatus, + PayTime = x.PayTime, + ACOOLYOrderNo = x.ACOOLYOrderNo, + CreationTime = x.CreationTime, + RefundApplyRemark = x.RefundApplyRemark, + ChannelName = x.ChannelName + }).OrderByDescending(r => r.CreationTime).ToListAsync(); + var i = 0; + result.ForEach(s => + { + s.SerialNumber = ++i; + s.LifePayOrderTypeStr = s.LifePayOrderType.GetDescription(); + s.CreationTimeStr = s.CreationTime.ToString(LifePaymentConstant.DateTimeFormatStr.yyyyMMddHHmm); + s.RechargeAmountStr = s.RechargeAmount.ToString("F2"); + s.PayAmountStr = s.PayAmount.ToString("F2"); + s.PayTimeStr = !s.PayTime.HasValue ? string.Empty : s.PayTime.Value.ToString(LifePaymentConstant.DateTimeFormatStr.yyyyMMddHHmm); + s.LifePayTypeStr = s.LifePayType.GetDescription(); + s.PayStatusStr = s.PayStatus.GetDescription(); + s.LifePayOrderStatusStr = s.LifePayOrderStatus.GetDescription(); + s.FinishTimeStr = !s.FinishTime.HasValue ? string.Empty : s.FinishTime.Value.ToString(LifePaymentConstant.DateTimeFormatStr.yyyyMMddHHmm); + }); + return result; + } + public async Task<string> GetBillErceiptExport(string orderNo) + { + try + { + var order = await _lifePayOrderRepository.Where(x => x.OrderNo == orderNo).FirstOrDefaultAsync(); + + CheckExtensions.IfTrueThrowUserFriendlyException(order == null, "鏈壘鍒拌鍗曚俊鎭�"); + if (order.LifePayType == LifePayTypeEnum.AliPay) + { + var elecInfoInput = new DataBillErceiptApplyInput + { + Type = "FUND_DETAIL", + Key = order.OutOrderNo + }; + + var elecInfoOutput = await _alipayInterfaceManager.DataBillErceiptApply(elecInfoInput); + if (elecInfoOutput != null) + { + var elecFileInput = new DataBillEreceiptQueryInput + { + FileId = elecInfoOutput.FileId, + }; + var elecFileOutput = await _alipayInterfaceManager.DataBillEreceiptQuery(elecFileInput); + if (!string.IsNullOrEmpty(elecFileOutput.DownloadUrl)) + { + return elecFileOutput.DownloadUrl; + } + return ""; + } + return ""; + } + else + { + WxPayTradeBillApplyRequest req = new WxPayTradeBillApplyRequest + { + OutBillNo = order.OutOrderNo, + }; + + var res = await _wxPayApi.WxPayTradeBillApply(req); + return ""; + } + } + catch (Exception ex) + { + _logger.LogError("鑾峰彇璁㈠崟鍙蜂负{0}鐢靛瓙鍥炲崟鍑虹幇閿欒锛歿1}", orderNo, ex.Message); + return ""; + } + } #endregion #region 鎿嶄綔 @@ -228,8 +798,14 @@ /// <returns></returns> public async Task<CreateLifePayOrderOutput> CreateLifePayPhoneOrder(CreateLifePayOrderInput<LifePhoneData> input) { + CheckExtensions.IfTrueThrowUserFriendlyException(input.ProductData.IspCode == "dianxin" && string.IsNullOrEmpty(input.ProductData.Name), "鐢典俊鎵嬫満鍙峰繀濉満涓诲悕"); + + var user = await _lifePayUserRepository.FirstOrDefaultAsync(x => x.Id == input.UserId); CheckExtensions.IfTrueThrowUserFriendlyException(user == null, "鐢ㄦ埛涓嶅瓨鍦紝璇峰厛鐧诲綍鍐嶆搷浣�"); + + var channle = await GetLifePayChannlesDtoByNum(input.ChannelId); + CheckExtensions.IfTrueThrowUserFriendlyException(channle == null, "娓犻亾涓嶅瓨鍦�"); var rate = await GetRate(); CheckExtensions.IfTrueThrowUserFriendlyException(rate.IsNullOrEmpty(), "鏈厤缃姌鎵�"); @@ -238,7 +814,7 @@ var orderInput = new CreateLifePayOrderInput { - OrderNo = CreateOrderNo(), + OrderNo = channle.ChannlesNum + CreateOrderNo(), LifePayOrderStatus = LifePayOrderStatusEnum.寰呯‘璁�, LifePayOrderType = LifePayOrderTypeEnum.璇濊垂璁㈠崟, //LifePayType = input.LifePayType, @@ -249,6 +825,7 @@ PayAmount = amount.PayAmont, DiscountAmount = amount.DiscountAmount, RechargeAmount = amount.RechargeAmount, + ChannelId = channle.ChannlesNum }; await CreateLifePayOrder(orderInput); @@ -270,6 +847,10 @@ var user = await _lifePayUserRepository.FirstOrDefaultAsync(x => x.Id == input.UserId); CheckExtensions.IfTrueThrowUserFriendlyException(user == null, "鐢ㄦ埛涓嶅瓨鍦紝璇峰厛鐧诲綍鍐嶆搷浣�"); + var channle = await GetLifePayChannlesDtoByNum(input.ChannelId); + CheckExtensions.IfTrueThrowUserFriendlyException(channle == null, "娓犻亾涓嶅瓨鍦�"); + CheckExtensions.IfTrueThrowUserFriendlyException(channle.Status == LifePayChannelsStatsEnum.绂佺敤, "娓犻亾宸茶绂佺敤"); + var rate = await GetRate(); CheckExtensions.IfTrueThrowUserFriendlyException(rate.IsNullOrEmpty(), "鏈厤缃姌鎵�"); @@ -277,7 +858,7 @@ var orderInput = new CreateLifePayOrderInput { - OrderNo = CreateOrderNo(), + OrderNo = channle.ChannlesNum + CreateOrderNo(), LifePayOrderStatus = LifePayOrderStatusEnum.寰呯‘璁�, LifePayOrderType = LifePayOrderTypeEnum.鐢佃垂璁㈠崟, // LifePayType = input.LifePayType, @@ -288,6 +869,51 @@ PayAmount = amount.PayAmont, DiscountAmount = amount.DiscountAmount, RechargeAmount = amount.RechargeAmount, + ChannelId = channle.ChannlesNum + }; + + await CreateLifePayOrder(orderInput); + + var result = new CreateLifePayOrderOutput() + { + OrderNo = orderInput.OrderNo, + }; + return result; + } + + /// <summary> + /// 鍒涘缓鐢熸椿缂磋垂鐕冩皵璁㈠崟 + /// </summary> + /// <param name="input"></param> + /// <returns></returns> + public async Task<CreateLifePayOrderOutput> CreateLifePayGasOrder(CreateLifePayOrderInput<LifeGasData> input) + { + var user = await _lifePayUserRepository.FirstOrDefaultAsync(x => x.Id == input.UserId); + CheckExtensions.IfTrueThrowUserFriendlyException(user == null, "鐢ㄦ埛涓嶅瓨鍦紝璇峰厛鐧诲綍鍐嶆搷浣�"); + + var channle = await GetLifePayChannlesDtoByNum(input.ChannelId); + CheckExtensions.IfTrueThrowUserFriendlyException(channle == null, "娓犻亾涓嶅瓨鍦�"); + CheckExtensions.IfTrueThrowUserFriendlyException(channle.Status == LifePayChannelsStatsEnum.绂佺敤, "娓犻亾宸茶绂佺敤"); + + var rate = await GetRate(); + CheckExtensions.IfTrueThrowUserFriendlyException(rate.IsNullOrEmpty(), "鏈厤缃姌鎵�"); + + var amount = CalculateAmount(input.ProductData.ParValue, rate.FirstOrDefault(x => x.RateType == LifePayRateTypeEnum.榛樿鐕冩皵鎶樻墸).Rate); + + var orderInput = new CreateLifePayOrderInput + { + OrderNo = channle.ChannlesNum + CreateOrderNo(), + LifePayOrderStatus = LifePayOrderStatusEnum.寰呯‘璁�, + LifePayOrderType = LifePayOrderTypeEnum.鐕冩皵璁㈠崟, + // LifePayType = input.LifePayType, + OrderParamDetailJsonStr = JsonConvert.SerializeObject(input.ProductData), + UserId = user.Id, + PayStatus = LifePayStatusEnum.鏈敮浠�, + PhoneNumber = user.PhoneNumber, + PayAmount = amount.PayAmont, + DiscountAmount = amount.DiscountAmount, + RechargeAmount = amount.RechargeAmount, + ChannelId = channle.ChannlesNum }; await CreateLifePayOrder(orderInput); @@ -323,6 +949,9 @@ break; case LifePayOrderTypeEnum.鐢佃垂璁㈠崟: desc += "鐢佃垂"; + break; + case LifePayOrderTypeEnum.鐕冩皵璁㈠崟: + desc += "鐕冩皵"; break; default: break; @@ -363,6 +992,9 @@ case LifePayOrderTypeEnum.鐢佃垂璁㈠崟: desc += "鐢佃垂"; break; + case LifePayOrderTypeEnum.鐕冩皵璁㈠崟: + desc += "鐕冩皵"; + break; default: break; } @@ -373,12 +1005,10 @@ // var result = await PayTransactionsJsAPI(input.OpenId, input.Attach, order.PayAmount, input.OrderNo, desc); - var result = await PayTransactionsJsAPI(input.OpenId, input.Attach, order.PayAmount, input.OrderNo, desc); + var result = await PayTransactionsJsAPI(input.OpenId, input.PayAppId, input.Attach, order.PayAmount, input.OrderNo, desc); return result; //var payUrl = await GetPayQRCode(order.LifePayType.Value, order.OrderNo, desc, 0.01m, ip, input.H5Type); //var payUrl = await GetPayQRCode(order.LifePayType.Value, order.OrderNo, desc, order.PayAmount, ip, input.H5Type); - - } @@ -454,14 +1084,46 @@ return (result.Code, requestInput.RequestNo, result.ElectricChargeOrder.BusiOrderNo); } - public async Task<ModelPaymentMiniPay> PayTransactionsJsAPI(string openid, string order_guid, decimal amount, string outTradeNo, string description) + /// <summary> + /// 鍒涘缓ACOOLY鐕冩皵璁㈠崟 + /// </summary> + /// <param name="input"></param> + /// <returns></returns> + public async Task<(string Code, string RequestNo, string ACOOLYOrderNo)> CreateACOOLYGasOrder(LifeGasData input, string orderNo) { - string time_expire = DateTime.Now.AddMinutes(5).ToString("yyyy-MM-ddTHH:mm:ss") + "+08:00";//璁㈠崟澶辨晥鏃堕棿 + var requestInput = new ConfirmGasOrderRequestInput() + { + GasOrgType = input.GasOrgType, + ParValue = input.ParValue, + GasAccount = input.GasAccount, + OutOrderNo = orderNo, + AreaName = input.Province + "-" + input.City + }; + var result = await _aCOOLYManager.ConfirmGasOrder(requestInput); +#if DEBUG + + _logger.LogInformation($"CreateACOOLYGasOrder:{JsonConvert.SerializeObject(result)}"); + +#endif + + CheckExtensions.IfTrueThrowUserFriendlyException(!result.Success || (result.Code != ACOOLYConstant.Code.SUCCESS && result.Code != ACOOLYConstant.Code.PROCESSING), + "璋冪敤ACOOLY鎺ュ彛ConfirmElectricOrder杩斿洖閿欒:" + JsonConvert.SerializeObject(result)); + + return (result.Code, requestInput.RequestNo, result.GasChargeOrder.BusiOrderNo); + } + + public async Task<ModelPaymentMiniPay> PayTransactionsJsAPI(string openid, string appId, string order_guid, decimal amount, string outTradeNo, string description) + { + string time_expire = DateTime.Now.AddMinutes(5).ToString("yyyy-MM-ddTHH:mm:ss") + "+08:00"; /// 璁㈠崟澶辨晥鏃堕棿 + if (string.IsNullOrEmpty(appId)) + { + appId = _wxPayOptions.AppID; + } + ModelMiniPayRequest req = new ModelMiniPayRequest { - TimeExpire = time_expire, - Appid = _wxPayOptions.AppID, + Appid = appId, Mchid = _wxPayOptions.Mchid, Attach = order_guid, Description = description, @@ -477,16 +1139,18 @@ OpenId = openid } }; + Logger.LogError("璋冪敤璇锋眰锛�" + req.ToJson()); var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds(); string nonce = Guid.NewGuid().ToString(); var res = await _wxPayApi.PayTransactionsJsAPI(req); + Logger.LogError("璋冪敤缁撴灉锛�" + res.ToJson()); string package = "prepay_id=" + res.PrepayId; ModelPaymentMiniPay info = new ModelPaymentMiniPay(); if (res != null) { - string paytext = BuildSignByPay(_wxPayOptions.AppID, timestamp, nonce, package); + string paytext = BuildSignByPay(appId, timestamp, nonce, package); string paysign = _wxPayApi.GeneratePaySignByKey(paytext); info.Timestamp = timestamp.ToString(); @@ -543,10 +1207,14 @@ case LifePayOrderTypeEnum.鐢佃垂璁㈠崟: result = await CreateACOOLYElectricOrder(JsonConvert.DeserializeObject<LifeElectricData>(order.OrderParamDetailJsonStr), order.OrderNo); break; + case LifePayOrderTypeEnum.鐕冩皵璁㈠崟: + result = await CreateACOOLYGasOrder(JsonConvert.DeserializeObject<LifeGasData>(order.OrderParamDetailJsonStr), order.OrderNo); + break; default: break; } + order.LifePayRefundStatus = LifePayRefundStatusEnum.鏃犻渶閫�娆�; order.LifePayOrderStatus = LifePayOrderStatusEnum.寰呯‘璁�; //SetOrderStatus(order, result.Code); order.OutRequestNo = result.RequestNo.IsNullOrEmpty() ? null : result.RequestNo; @@ -556,7 +1224,7 @@ { _logger.LogError(ex, "澶勭悊鐢熸椿缂磋垂鏀粯鎴愬姛鍥炶皟鏃跺紓甯�"); order.LifePayOrderStatus = LifePayOrderStatusEnum.宸插け璐�; - order.PayStatus = LifePayStatusEnum.寰呴��娆�; + order.LifePayRefundStatus = LifePayRefundStatusEnum.寰呴��娆�; } _logger.LogError("鐢熸椿缂磋垂璁㈠崟鐘舵�侊細" + order.LifePayOrderStatus.ToString()); await _lifePayOrderRepository.UpdateAsync(order); @@ -568,7 +1236,7 @@ /// <param name="orderNo"></param> /// <param name="outOrderNo"></param> /// <returns></returns> - public async Task ACOOLYOrderNotifyHandler(string orderNo, string acoolyOrderNo, LifePayOrderStatusEnum status) + public async Task ACOOLYOrderNotifyHandler(string orderNo, string acoolyOrderNo, LifePayOrderStatusEnum status, ACOOLYStatusEnum acoolyStatus, decimal payAmount) { var order = await _lifePayOrderRepository.Where(x => x.OrderNo == orderNo).FirstOrDefaultAsync(); CheckExtensions.IfTrueThrowUserFriendlyException(order == null, "璁㈠崟涓嶅瓨鍦�"); @@ -578,7 +1246,7 @@ return; } - order.LifePayOrderStatus = status; + order.PlatformDeductionAmount = payAmount; if (acoolyOrderNo.IsNotNullOrEmpty()) { order.ACOOLYOrderNo = acoolyOrderNo; @@ -593,6 +1261,9 @@ { order.PayStatus = LifePayStatusEnum.寰呴��娆�; } + + order.LifePayOrderStatus = status; + order.ACOOLYStatus = acoolyStatus; await _lifePayOrderRepository.UpdateAsync(order); } @@ -613,25 +1284,386 @@ return; } - if (order.LifePayOrderStatus != LifePayOrderStatusEnum.宸插け璐� && order.PayStatus != LifePayStatusEnum.寰呴��娆�) + if (order.LifePayOrderStatus != LifePayOrderStatusEnum.宸插け璐� && order.PayStatus != LifePayStatusEnum.寰呴��娆� && order.LifePayOrderStatus != LifePayOrderStatusEnum.閫�娆惧緟瀹℃牳) { throw new UserFriendlyException("褰撳墠璁㈠崟鐘舵�佹棤娉曢��娆�"); } - order.PayStatus = LifePayStatusEnum.宸查��娆�; + var outRefundNo = order.ChannelId + CreateRefundOrderNo(); + order.RefundOrderNo = outRefundNo; + switch (order.LifePayType) + { + case LifePayTypeEnum.WxPay: + var wxRefundResult = await WxPayDomesticRefunds(order.OrderNo, outRefundNo,order.RefundApplyRemark, Convert.ToInt32(order.PayAmount * 100), Convert.ToInt32(order.PayAmount * 100)); + if (wxRefundResult.Status == "SUCCESS") + { + order.PayStatus = LifePayStatusEnum.宸查��娆�; + order.LifePayOrderStatus = LifePayOrderStatusEnum.宸查��娆�; + order.LifePayRefundStatus = LifePayRefundStatusEnum.宸查��娆�; + } + else if (wxRefundResult.Status == "PROCESSING") + { + order.PayStatus = LifePayStatusEnum.閫�娆句腑; + order.LifePayOrderStatus = LifePayOrderStatusEnum.閫�娆句腑; + order.LifePayRefundStatus = LifePayRefundStatusEnum.閫�娆句腑; + } + else + { + order.PayStatus = LifePayStatusEnum.寰呴��娆�; + order.LifePayOrderStatus = LifePayOrderStatusEnum.閫�娆惧け璐�; + order.LifePayRefundStatus = LifePayRefundStatusEnum.寰呴��娆�; + } + + break; + case LifePayTypeEnum.AliPay: + var aliRefundResult = await AliTradeRefund(new AlipayTradeRefundRequest() { OutTradeNo = order.OrderNo, RefundAmount = order.PayAmount.ToString() }); + if (aliRefundResult.Code != AlipayResultCode.Success) + { + throw new UserFriendlyException("閫�娆惧け璐�"); + } + + order.PayStatus = LifePayStatusEnum.宸查��娆�; + order.LifePayOrderStatus = LifePayOrderStatusEnum.宸查��娆�; + break; + default: throw new UserFriendlyException("閫�娆惧け璐�"); + } + order.RefundCredentialsImgUrl = input.RefundCredentialsImgUrl; + order.RefundCheckRemark = input.RefundCheckRemark; order.RefundTime = DateTime.Now; + order.RefundCheckUserId = CurrentUser.Id; + order.RefundPrice = order.PayAmount; await _lifePayOrderRepository.UpdateAsync(order); #region 璁板綍鏃ュ織 - await PublishLifePayOrderHistoryEvent("閫�娆�", "閫�娆�", order.Id); + await LifePayOrderHistory("閫�娆�", "閫�娆�", order.Id, (int)OperateHistoryTypeEnum.LifePayRefund); #endregion } + /// <summary> + /// 鐢ㄦ埛鍙戣捣鐢熸椿缂磋垂閫�娆� + /// </summary> + /// <param name="input"></param> + /// <returns></returns> + /// <exception cref="UserFriendlyException"></exception> + public async Task RefundUserLifePayOrder(RefundUserLifePayOrderInput input) + { + var order = await _lifePayOrderRepository.FirstOrDefaultAsync(x => x.Id == input.Id); + CheckExtensions.IfTrueThrowUserFriendlyException(order == null, "璁㈠崟涓嶅瓨鍦�"); + if (order.UserId != input.UserId) + { + throw new UserFriendlyException("闈炵敤鎴锋湰浜洪��娆�"); + } + + if (order.PayStatus == LifePayStatusEnum.宸查��娆�) + { + return; + } + + if (order.LifePayOrderStatus != LifePayOrderStatusEnum.寰呯‘璁� && order.LifePayOrderStatus != LifePayOrderStatusEnum.宸插け璐� + && order.PayStatus != LifePayStatusEnum.宸叉敮浠�) + { + throw new UserFriendlyException("褰撳墠璁㈠崟鐘舵�佹棤娉曠敵璇烽��娆�"); + } + + order.LifePayOrderStatus = LifePayOrderStatusEnum.閫�娆惧緟瀹℃牳; + order.RefundApplyRemark = input.RefundApplyRemark; + order.RefundApplyTime = DateTime.Now; + + await _lifePayOrderRepository.UpdateAsync(order); + } + + /// <summary> + /// 寰俊閫�娆� + /// </summary> + /// <param name="outTradeNo"></param> + /// <param name="reason"></param> + /// <param name="refund"></param> + /// <param name="total"></param> + /// <param name="currency"></param> + /// <returns></returns> + public async Task<WxPayDomesticRefundsReponse> WxPayDomesticRefunds(string outTradeNo,string outRefundNo, string reason, int refund, int total, string currency = "CNY") + { + WxPayDomesticRefundsRequest req = new WxPayDomesticRefundsRequest + { + OutTradeNo = outTradeNo, + OutRefundNo = outRefundNo, + Reason = reason, + Amount = new Model_WxPayDomesticRefunds_Amount + { + Refund = refund, + Total = total, + Currency = "CNY" + }, + NotifyUrl = $"{_wxPayOptions.NotifyUrl}{LifePaymentConstant.WxPayDomesticRefundsNotifySectionUrl}", + }; + + var res = await _wxPayApi.WxPayDomesticRefunds(req); + return res; + } + + private async Task<AlipayTradeRefundResponse> AliTradeRefund(AlipayTradeRefundRequest input) + { + return await _aliPayApi.TradeRefund(input); + } + + public async Task<int> AddUpdateUserAccount(AddUpdateUserAccountInput input) + { + var user = await _lifePayUserRepository.Where(r => r.Id == input.UserId && !r.IsDeleted).FirstOrDefaultAsync(); + CheckExtensions.IfTrueThrowUserFriendlyException(user == null, "鐢ㄦ埛涓嶅瓨鍦�"); + + if (input.Id.HasValue) + { + var userAccount = await _lifePayAccount.Where(x => x.UserId == input.UserId && x.Id == input.Id) + .FirstOrDefaultAsync(); + CheckExtensions.IfTrueThrowUserFriendlyException(userAccount == null, "鎴峰彿涓嶅瓨鍦�"); + var repeatAccountContent = await _lifePayAccount.Where(x => x.UserId == input.UserId && x.LifePayType == input.LifePayType && x.Content == input.Content && x.Id != input.Id) + .FirstOrDefaultAsync(); + CheckExtensions.IfTrueThrowUserFriendlyException(repeatAccountContent != null, "鎴峰彿宸插瓨鍦�"); + + userAccount.LifePayType = input.LifePayType; + userAccount.Content = input.Content; + userAccount.Province = input.Province; + userAccount.City = input.City; + userAccount.Remark = input.Remark; + userAccount.Operators = input.Operators; + userAccount.ExtraProperties = input.ExtraProperties; + } + else + { + var repeatAccountContent = await _lifePayAccount.Where(x => x.UserId == input.UserId && x.LifePayType == input.LifePayType && x.Content == input.Content) + .FirstOrDefaultAsync(); + CheckExtensions.IfTrueThrowUserFriendlyException(repeatAccountContent != null, "鎴峰彿宸插瓨鍦�"); + var userAccount = new LifePayAccount + { + Id = Guid.NewGuid(), + UserId = input.UserId, + Content = input.Content, + Province = input.Province, + LifePayType = input.LifePayType, + City = input.City, + Remark = input.Remark, + Operators = input.Operators, + ExtraProperties = input.ExtraProperties, + }; + await _lifePayAccount.InsertAsync(userAccount); + } + + if (input.LifePayType == LifePayOrderTypeEnum.璇濊垂璁㈠崟) + { + var extraProperties = JsonConvert.DeserializeObject<Model_UserAccountExtraProperties>(input.ExtraProperties); + if (!string.IsNullOrEmpty(extraProperties.Name)) + { + user.Name = extraProperties.Name; + } + } + + + return Constant.SUCCESS; + } + + /// <summary> + /// 鐢ㄦ埛鍒犻櫎鎴峰彿淇℃伅 + /// </summary> + /// <param name="input"></param> + /// <returns></returns> + public async Task<int> DeleteUserAccount(Guid id) + { + var userAccount = await _lifePayAccount.Where(x => x.Id == id) + .FirstOrDefaultAsync(); + CheckExtensions.IfTrueThrowUserFriendlyException(userAccount == null, "鎴峰彿涓嶅瓨鍦�"); + userAccount.DeleterId = userAccount.UserId; + userAccount.DeletionTime = DateTime.Now; + userAccount.IsDeleted = true; + return Constant.SUCCESS; + } + + /// <summary> + /// 閫�娆鹃┏鍥� + /// </summary> + /// <param name="input"></param> + /// <returns></returns> + /// <exception cref="UserFriendlyException"></exception> + public async Task RejectRefundLifePayOrder(RefundLifePayOrderInput input) + { + var order = await _lifePayOrderRepository.FirstOrDefaultAsync(x => x.Id == input.Id); + CheckExtensions.IfTrueThrowUserFriendlyException(order == null, "璁㈠崟涓嶅瓨鍦�"); + + if (order.PayStatus == LifePayStatusEnum.宸查��娆�) + { + return; + } + + if ((order.LifePayOrderStatus == LifePayOrderStatusEnum.宸插け璐� && order.PayStatus == LifePayStatusEnum.寰呴��娆�) || + order.LifePayOrderStatus == LifePayOrderStatusEnum.閫�娆惧緟瀹℃牳 || order.LifePayOrderStatus == LifePayOrderStatusEnum.寰呯‘璁�) + { + order.LifePayOrderStatus = LifePayOrderStatusEnum.閫�娆惧け璐�; + order.RefundCheckRemark = input.RefundCheckRemark; + order.RefundCheckUserId = CurrentUser.Id; + + await _lifePayOrderRepository.UpdateAsync(order); + + #region 璁板綍鏃ュ織 + + await PublishLifePayOrderHistoryEvent("閫�娆鹃┏鍥�", "閫�娆�", order.Id); + + #endregion + } + else + { + throw new UserFriendlyException("褰撳墠璁㈠崟鐘舵�佹棤娉曢��娆�"); + } + + + } + + public async Task CreateEditPayChannels(CreateEditPayChannelsInput input) + { + if (input.Id.HasValue) + { + var dto = await _lifePayChannlesRep.FirstOrDefaultAsync(r => r.Id == input.Id.Value); + CheckExtensions.IfTrueThrowUserFriendlyException(dto == null, "鏈幏鍙栧埌娓犻亾鎶樻墸鏁版嵁"); + dto.ChannlesName = input.ChannlesName; + dto.ChannlesNum = input.ChannlesNum; + dto.ChannlesRate = input.ChannlesRate; + dto.ChannlesRakeRate = input.ChannlesRakeRate; + dto.SwitchType = input.SwitchType; + dto.ChannlesType = input.ChannlesType; + dto.Status = input.Status; + #region 璁板綍鏃ュ織 + + await PublishLifePayOrderHistoryEvent("娓犻亾绠$悊", "缂栬緫", input.Id.Value, TableType.LifePayChannles); + + #endregion + } + else + { + CheckExtensions.IfTrueThrowUserFriendlyException(input.ChannlesRate < 0.01m, "娓犻亾鎶樻墸璁剧疆閿欒"); + input.Id = Guid.NewGuid(); + var entity = ObjectMapper.Map<CreateEditPayChannelsInput, LifePayChannles>(input); + await _lifePayChannlesRep.InsertAsync(entity); + + #region 璁板綍鏃ュ織 + + await PublishLifePayOrderHistoryEvent("娓犻亾绠$悊", "鏂板", input.Id.Value, TableType.LifePayChannles); + + #endregion + } + + + } + + public async Task SetLifePayChannelsStatus(Guid id, LifePayChannelsStatsEnum status) + { + await _lifePayChannlesRep.Where(r => r.Id == id).UpdateAsync(r => new LifePayChannles + { + Status = status, + }); + + #region 璁板綍鏃ュ織 + + await PublishLifePayOrderHistoryEvent("娓犻亾绠$悊", status.GetDescription(), id, TableType.LifePayChannles); + + #endregion + } + + public async Task<bool> CheckChannelsStatus(string channlesId) + { + var dto = await _lifePayChannlesRep.FirstOrDefaultAsync(r => r.ChannlesNum == channlesId); + CheckExtensions.IfTrueThrowUserFriendlyException(dto == null, "褰撳墠娓犻亾鍟嗕笉瀛樺湪"); + CheckExtensions.IfTrueThrowUserFriendlyException(dto.Status == LifePayChannelsStatsEnum.绂佺敤, "褰撳墠娓犻亾鍟嗗凡绂佺敤"); + return true; + } + + public async Task CreateEditLifePayRate(List<LifePayRateInput> input) + { + CheckExtensions.IfTrueThrowUserFriendlyException(input.Where(r => r.Rate <= 0).Any(), "鎶樻墸涓嶅緱灏忎簬绛変簬0"); + var baseRate = input.FirstOrDefault(r => r.RateType == LifePayRateTypeEnum.渚涘簲鍟嗘姌鎵d环)?.Rate; + var listData = new List<LifePayRate>(); + foreach (var item in input) + { + CheckExtensions.IfTrueThrowUserFriendlyException(item.Rate < (baseRate ?? 0), "鎶樻墸涓嶅緱灏忎簬渚涘簲鍟嗘姌鎵�"); + var tmpDto = await _lifePayRateRepository.FirstOrDefaultAsync(r => r.RateType == item.RateType); + if (tmpDto != null) + { + tmpDto.Rate = item.Rate; + } + else + { + listData.Add(new LifePayRate + { + CreationTime = DateTime.Now, + Rate = item.Rate, + RateType = item.RateType, + Id = Guid.NewGuid(), + }); + } + } + + if (listData.Any()) + { + await _lifePayRateRepository.InsertManyAsync(listData); + } + } + + public async Task CreateEditLifePayPremium(List<LifePayPremiumInput> input) + { + CheckExtensions.IfTrueThrowUserFriendlyException(input.Where(r => r.Rate < 0).Any(), "鎶樻墸涓嶅緱灏忎簬0"); + var listData = new List<LifePayPremium>(); + foreach (var item in input) + { + var tmpDto = await _lifePayPremiumRepository.FirstOrDefaultAsync(r => r.PremiumType == item.PremiumType); + if (tmpDto != null) + { + tmpDto.Rate = item.Rate; + } + else + { + listData.Add(new LifePayPremium + { + CreationTime = DateTime.Now, + Rate = item.Rate, + PremiumType = item.PremiumType, + Id = Guid.NewGuid(), + }); + } + } + + if (listData.Any()) + { + await _lifePayPremiumRepository.InsertManyAsync(listData); + } + } + + public async Task EditIntroInfo(LifePayIntroInfoInput input) + { + var listData = new List<LifePayIntroInfo>(); + foreach (var item in input.Data) + { + var tmpDto = await _lifePayIntroInfoRepository.Where(r => r.LifePayType == input.LifePayType).DeleteAsync(); + + listData.Add(new LifePayIntroInfo + { + LifePayType = input.LifePayType, + CreationTime = DateTime.Now, + Type = item.Type, + ContentSummary = item.ContentSummary, + Content = item.Content, + Path = item.Path, + Sequence = item.Sequence, + Id = Guid.NewGuid(), + }); + } + + if (listData.Any()) + { + await _lifePayIntroInfoRepository.InsertManyAsync(listData); + } + } #endregion #region 绉佹湁 @@ -641,9 +1673,19 @@ return "JF" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + GlobalRandom.GetRandomNum(4); } + private string CreateRefundOrderNo() + { + return "JFTK" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + GlobalRandom.GetRandomNum(4); + } + private (decimal PayAmont, decimal DiscountAmount, decimal RechargeAmount) CalculateAmount(decimal amount, decimal rate) { - var payAmount = decimal.Round(amount * rate, 2, MidpointRounding.AwayFromZero); + /// 姝e父鏀粯 + //var payAmount = decimal.Round(amount * rate / 100, 2, MidpointRounding.AwayFromZero); + + /// 1鍒嗛挶鏀粯 + decimal payAmount = 0.01m; + CheckExtensions.IfTrueThrowUserFriendlyException(payAmount < 0.01m, "鏀粯閲戦閿欒"); return (payAmount, amount - payAmount, amount); @@ -684,6 +1726,20 @@ await _distributedEventBus.PublishAsync(recordEto, false); } + private async Task LifePayOrderHistory(string operateContent, string operateName, Guid relationId, int? tableType = (int)OperateHistoryTypeEnum.LifePayRefund) + { + var operateHistory = new OperateHistory + { + CreatorName = CurrentUser.Name, + OperateContent = operateName, + OperateName = operateName, + RelationId = relationId, + TableType = tableType + + }; + await _operateHistory.InsertAsync(operateHistory); + } + /// <summary> /// 鑾峰彇鏀粯浜岀淮鐮� /// </summary> @@ -697,9 +1753,6 @@ { var codeUrl = string.Empty; switch (payType) - - - { case LifePayTypeEnum.AliPay: codeUrl = await GetAliPayQRCode(outTradeNo, description, amount); @@ -765,7 +1818,6 @@ CheckExtensions.IfTrueThrowUserFriendlyException(amount <= 0, CustomeErrorMessage.SometingMustSometing, "鑾峰彇鏀粯浜岀淮鐮佹椂閲戦", "澶т簬0"); - var res = await _wxPayApi.PayTransactionsH5(new PayTransactionsNativeH5 { Appid = _wxPayOptions.AppID, @@ -818,6 +1870,7 @@ return res.QrCode; } + /// <summary> /// 鏋勯�犲緟绛惧悕瀛楃涓� /// </summary> @@ -834,5 +1887,62 @@ } + private async Task<IQueryable<LifePayOrderListOutput>> GetLifePayOrderListFilter(QueryLifePayOrderListInput input) + { + var result = (from a in _lifePayOrderRepository.Where(x => x.PayStatus != LifePayStatusEnum.鏈敮浠�) + .WhereIf(input.BeginFinishTime.HasValue, x => x.FinishTime >= input.BeginFinishTime) + .WhereIf(input.EndFinishTime.HasValue, x => x.FinishTime <= input.EndFinishTime) + .WhereIf(input.BeginPayTime.HasValue, x => x.PayTime >= input.BeginPayTime) + .WhereIf(input.EndPayTime.HasValue, x => x.PayTime <= input.EndPayTime) + .WhereIf(input.LifePayOrderStatus.HasValue, x => x.LifePayOrderStatus == input.LifePayOrderStatus.Value) + .WhereIf(input.PayStatus.HasValue, x => x.PayStatus == input.PayStatus.Value) + .WhereIf(input.LifePayOrderType.HasValue, x => x.LifePayOrderType == input.LifePayOrderType.Value) + .WhereIf(input.UserId.HasValue, x => x.UserId == input.UserId.Value) + .WhereIf(input.KeyWords.IsNotNullOrEmpty(), x => x.PhoneNumber.Contains(input.KeyWords) || x.OrderNo.Contains(input.KeyWords) || x.OutOrderNo.Contains(input.KeyWords) || x.ACOOLYOrderNo.Contains(input.KeyWords)) + join b in _lifePayChannlesRep on a.ChannelId equals b.ChannlesNum into temp + from b in temp.DefaultIfEmpty() + select new LifePayOrderListOutput + { + DiscountAmount = a.DiscountAmount, + FinishTime = a.FinishTime, + Id = a.Id, + LifePayOrderStatus = a.LifePayOrderStatus, + LifePayOrderType = a.LifePayOrderType, + LifePayType = a.LifePayType, + OrderNo = a.OrderNo, + PayAmount = a.PayAmount, + PhoneNumber = a.PhoneNumber, + RechargeAmount = a.RechargeAmount, + UserId = a.UserId, + OutOrderNo = a.OutOrderNo, + PayStatus = a.PayStatus, + PayTime = a.PayTime, + ACOOLYOrderNo = a.ACOOLYOrderNo, + RefundCredentialsImgUrl = a.RefundCredentialsImgUrl.GetOssPath(), + CreationTime = a.CreationTime, + RefundCheckRemark = a.RefundCheckRemark, + RefundApplyRemark = a.RefundApplyRemark, + RefundTime = a.RefundTime, + ChannelName = b.ChannlesName + }); + return result; + } + + private IQueryable<CreateEditPayChannelsInput> GetLifePayChannlesListFilter() + { + return _lifePayChannlesRep.Select(x => + new CreateEditPayChannelsInput + { + Id = x.Id, + ChannlesRate = x.ChannlesRate, + ChannlesRakeRate = x.ChannlesRakeRate, + ChannlesName = x.ChannlesName, + ChannlesNum = x.ChannlesNum, + Status = x.Status, + SwitchType = x.SwitchType, + ChannlesType = x.ChannlesType, + }); + } + #endregion } -- Gitblit v1.9.1