using Aop.Api.Domain; using ApiTools.Core; using Consul; using Furion.FriendlyException; using Mapster; using Medallion.Threading; using MediatR; using Microsoft.EntityFrameworkCore; using StackExchange.Redis; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ApiTools.Application { public class ChannelWalletCommandHandler( IDistributedLockProvider distributedLockProvider, ChannelWalletRepository channelWalletRepository, ChannelWalletTransactionRepository channelWalletTransactionRepository, ChannelWalletService channelWalletService ) : IRequestHandler, IRequestHandler { private readonly IDistributedLockProvider distributedLockProvider = distributedLockProvider; private readonly ChannelWalletRepository channelWalletRepository = channelWalletRepository; private readonly ChannelWalletTransactionRepository channelWalletTransactionRepository = channelWalletTransactionRepository; private readonly ChannelWalletService channelWalletService = channelWalletService; public async Task Handle(SaveChannelPingAnPayWalletCommand request, CancellationToken cancellationToken) { var logier = JwtUtils.GetCurrentLogier(); var wallet = await channelWalletRepository.GetQueryable(false) .Where(it => it.ChannelId == logier.ChannelId && it.OutWalletId == request.OutWalletId) .FirstOrDefaultAsync(); if (wallet == null) { wallet = new ChannelWallet(); wallet.ChannelId = logier.ChannelId; wallet.Access = EnumWalletAccess.PingAnPay; wallet.SignStatus = EnumWalletSignStatus.Normal; request.Adapt(wallet); await channelWalletRepository.SetCode(wallet); await channelWalletRepository.InsertNowAsync(wallet); } else { request.Adapt(wallet); await channelWalletRepository.UpdateNowAsync(wallet); } await channelWalletService.GetEnterpriseWalletBalance(wallet); return new SaveChannelPingAnPayWalletCommandResult { WalletId = wallet.Id, Balance = wallet.Balance, ErrorCode = wallet.ErrorCode, FailReason = wallet.FailReason }; } /// /// 提交渠道钱包转账 /// /// /// /// public async Task Handle(SubmitChannelWalletTransferCommand request, CancellationToken cancellationToken) { var logier = JwtUtils.GetCurrentLogier(); await using var handle = await distributedLockProvider.TryAcquireAsync( channelWalletService.GetLockKey(logier.ChannelId.Value, request.OutWalletId), TimeSpan.FromMinutes(30)); if (handle == null) throw Oops.Oh(EnumErrorCodeType.s429); var wallet = await channelWalletRepository.GetQueryable(false) .Where(it => it.ChannelId == logier.ChannelId && it.OutWalletId == request.OutWalletId) .FirstOrDefaultAsync(); if (wallet == null) throw Oops.Oh(EnumErrorCodeType.s404, "未开通钱包"); await channelWalletService.GetEnterpriseWalletBalance(wallet); if (request.Amount > wallet.Balance) throw Oops.Oh(EnumErrorCodeType.s404, "余额不足"); var checkExist = await channelWalletTransactionRepository.GetQueryable() .AnyAsync(it => it.WalletId == wallet.Id && it.OutCode == request.OutCode); if (checkExist) throw Oops.Oh(EnumErrorCodeType.s405, "交易单号"); var transaction = new ChannelWalletTransaction(); transaction.Type = EnumWalletTransactionType.Transfer; transaction.WalletId = wallet.Id; transaction.OutCode = request.OutCode; transaction.ConcurrencyLock = $"{logier.ChannelId}:{transaction.OutCode}"; transaction.Amount = request.Amount; transaction.Remark = request.Remark; transaction.TransactionStatus = EnumWalletTransactionStatus.WaitSubmit; transaction.Balance = wallet.Balance; transaction.AfterBalance = wallet.Balance - transaction.Amount; transaction.OutOperatorId = request.OutOperatorId; transaction.OperatorTime = request.OperatorTime; transaction.PayerName = wallet.Name; transaction.PayerAccount = wallet.Identity; transaction.PayerBank = wallet.Bank; transaction.PayerBankBranch = wallet.BankBranch; transaction.OutReceiveId = request.OutReceiveId; transaction.ReceiveBank = request.ReceiveBank; transaction.ReceiveBankBranch = request.ReceiveBankBranch; transaction.ReceiveName = request.ReceiveName; transaction.ReceiveIdentity = request.ReceiveIdentity; transaction.ReceiveAccount = request.ReceiveAccount; transaction.Currency = request.Currency; transaction.Purpose = request.Purpose; transaction.Remark = request.Remark; await channelWalletTransactionRepository.SetCode(transaction); await channelWalletTransactionRepository.InsertNowAsync(transaction); await channelWalletService.Transfer(wallet, transaction); return new SubmitChannelWalletTransferCommandResult { Id = transaction.Id, Code = transaction.Code, TransactionStatus = transaction.TransactionStatus, ErrorCode = transaction.ErrorCode, FailReason = transaction.FailReason, }; } } }