diff --git a/src/CMSMicroservice.Application/DayaLoanCQ/Commands/CheckDayaLoanStatus/CheckDayaLoanStatusCommandHandler.cs b/src/CMSMicroservice.Application/DayaLoanCQ/Commands/CheckDayaLoanStatus/CheckDayaLoanStatusCommandHandler.cs new file mode 100644 index 0000000..e25975c --- /dev/null +++ b/src/CMSMicroservice.Application/DayaLoanCQ/Commands/CheckDayaLoanStatus/CheckDayaLoanStatusCommandHandler.cs @@ -0,0 +1,121 @@ +using CMSMicroservice.Domain.Enums; +using CMSMicroservice.Application.DayaLoanCQ.Services; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.DayaLoanCQ.Commands.CheckDayaLoanStatus; + +/// +/// این Handler فقط وظیفه استعلام از API دایا و به‌روزرسانی DayaLoanContracts را دارد. +/// پردازش مالی (شارژ کیف پول، ثبت Order و...) توسط Worker و ProcessDayaLoanApprovalCommand انجام می‌شود. +/// +public class CheckDayaLoanStatusCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly IDayaLoanApiService _dayaApiService; + private readonly ILogger _logger; + + public CheckDayaLoanStatusCommandHandler( + IApplicationDbContext context, + IDayaLoanApiService dayaApiService, + ILogger logger) + { + _context = context; + _dayaApiService = dayaApiService; + _logger = logger; + } + + public async Task Handle(CheckDayaLoanStatusCommand request, CancellationToken cancellationToken) + { + var results = new List(); + + try + { + // فراخوانی سرویس دایا (Mock یا Real) + var dayaResults = await _dayaApiService.CheckLoanStatusAsync(request.NationalCodes, cancellationToken); + + foreach (var dayaResult in dayaResults) + { + try + { + results.Add(new DayaLoanStatusItem + { + NationalCode = dayaResult.NationalCode, + Status = dayaResult.Status, + ContractNumber = dayaResult.ContractNumber, + Message = "استعلام موفق" + }); + + // ذخیره یا به‌روزرسانی در دیتابیس (فقط اطلاعات قرارداد - بدون پردازش مالی) + var existingContract = await _context.DayaLoanContracts + .FirstOrDefaultAsync(d => d.NationalCode == dayaResult.NationalCode, cancellationToken); + + if (existingContract != null) + { + // به‌روزرسانی قرارداد موجود + existingContract.LastCheckDate = DateTime.Now; + existingContract.Status = dayaResult.Status; + existingContract.ContractNumber = dayaResult.ContractNumber; + + _logger.LogDebug( + "Updated DayaLoanContract for NationalCode {NationalCode}, Status: {Status}", + dayaResult.NationalCode, dayaResult.Status); + } + else + { + // ایجاد رکورد جدید قرارداد + var user = await _context.Users + .FirstOrDefaultAsync(u => u.NationalCode == dayaResult.NationalCode, cancellationToken); + + if (user != null) + { + var newContract = new DayaLoanContract + { + UserId = user.Id, + NationalCode = dayaResult.NationalCode, + Status = dayaResult.Status, + ContractNumber = dayaResult.ContractNumber, + LastCheckDate = DateTime.Now, + IsProcessed = false // پردازش مالی توسط Worker انجام می‌شود + }; + + await _context.DayaLoanContracts.AddAsync(newContract, cancellationToken); + + _logger.LogInformation( + "Created new DayaLoanContract for User {UserId}, NationalCode: {NationalCode}, Status: {Status}", + user.Id, dayaResult.NationalCode, dayaResult.Status); + } + } + + await _context.SaveChangesAsync(cancellationToken); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error processing Daya result for {NationalCode}", dayaResult.NationalCode); + } + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Error calling Daya API service"); + + // در صورت خطا، نتایج خالی برمی‌گردانیم + foreach (var nationalCode in request.NationalCodes) + { + results.Add(new DayaLoanStatusItem + { + NationalCode = nationalCode, + Status = DayaLoanStatus.PendingReceive, + ContractNumber = null, + Message = $"خطا در استعلام: {ex.Message}" + }); + } + } + + return new CheckDayaLoanStatusResponseDto + { + Results = results, + TotalChecked = request.NationalCodes.Count, + SuccessCount = results.Count(r => r.ContractNumber != null) + }; + } +} diff --git a/src/CMSMicroservice.Application/DayaLoanCQ/Commands/ProcessDayaLoanApproval/ProcessDayaLoanApprovalCommandHandler.cs b/src/CMSMicroservice.Application/DayaLoanCQ/Commands/ProcessDayaLoanApproval/ProcessDayaLoanApprovalCommandHandler.cs new file mode 100644 index 0000000..6d9651b --- /dev/null +++ b/src/CMSMicroservice.Application/DayaLoanCQ/Commands/ProcessDayaLoanApproval/ProcessDayaLoanApprovalCommandHandler.cs @@ -0,0 +1,202 @@ +using CMSMicroservice.Domain.Events; +using CMSMicroservice.Domain.Enums; +using CMSMicroservice.Domain.Common; +using CMSMicroservice.Application.Common.Interfaces; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.DayaLoanCQ.Commands.ProcessDayaLoanApproval; + +public class ProcessDayaLoanApprovalCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly IKavenegarService _smsService; + private readonly ILogger _logger; + + public ProcessDayaLoanApprovalCommandHandler( + IApplicationDbContext context, + IKavenegarService smsService, + ILogger logger) + { + _context = context; + _smsService = smsService; + _logger = logger; + } + + public async Task Handle(ProcessDayaLoanApprovalCommand request, CancellationToken cancellationToken) + { + // پیدا کردن کاربر + var user = await _context.Users + .Include(u => u.UserWallets) + .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken); + + if (user == null) + { + throw new NotFoundException(nameof(User), request.UserId); + } + + // چک کردن که قبلاً دریافت نکرده باشد + if (user.HasReceivedDayaCredit) + { + throw new InvalidOperationException($"کاربر {request.UserId} قبلاً اعتبار دایا را دریافت کرده است"); + } + + // ایجاد تراکنش با RefId = شماره قرارداد دایا + var transaction = new Transaction + { + Amount = request.WalletAmount , // 168 میلیون + Description = $"دریافت اعتبار دایا - قرارداد {request.ContractNumber}", + PaymentStatus = PaymentStatus.Success, + PaymentDate = DateTime.Now, + RefId = request.ContractNumber, // شماره قرارداد دایا + Type = TransactionType.DepositExternal1 + }; + + await _context.Transactions.AddAsync(transaction, cancellationToken); + await _context.SaveChangesAsync(cancellationToken); + + // یافتن یا ایجاد کیف پول کاربر + var wallet = user.UserWallets.FirstOrDefault(); + if (wallet == null) + { + wallet = new UserWallet + { + UserId = request.UserId, + Balance = 0, + NetworkBalance = 0, + DiscountBalance = 0 + }; + await _context.UserWallets.AddAsync(wallet, cancellationToken); + await _context.SaveChangesAsync(cancellationToken); + } + + // شارژ کیف پول عادی (56 میلیون) + var balanceBeforeMain = wallet.Balance; + wallet.Balance += request.WalletAmount; + + // لاگ کیف پول عادی + var mainLog = new UserWalletChangeLog + { + WalletId = wallet.Id, + CurrentBalance = wallet.Balance, + ChangeValue = request.WalletAmount, + CurrentNetworkBalance = wallet.NetworkBalance, + ChangeNerworkValue = 0, + IsIncrease = true, + RefrenceId = transaction.Id + }; + await _context.UserWalletChangeLogs.AddAsync(mainLog, cancellationToken); + + + + // شارژ کیف پول تخفیف (56 میلیون) + var balanceBeforeDiscount = wallet.DiscountBalance; + wallet.DiscountBalance += request.DiscountWalletAmount; + + // لاگ کیف پول تخفیف + var discountLog = new UserWalletChangeLog + { + WalletId = wallet.Id, + CurrentBalance = wallet.Balance, + ChangeValue = 0, + CurrentNetworkBalance = wallet.NetworkBalance, + ChangeNerworkValue = 0, + CurrentDiscountBalance = wallet.DiscountBalance, + ChangeDiscountValue = request.DiscountWalletAmount, + IsIncrease = true, + RefrenceId = transaction.Id + }; + await _context.UserWalletChangeLogs.AddAsync(discountLog, cancellationToken); + + // به‌روزرسانی وضعیت کاربر + user.HasReceivedDayaCredit = true; + user.DayaCreditReceivedAt = DateTime.Now; + + // تنظیم نحوه خرید پکیج به DayaLoan + user.PackagePurchaseMethod = PackagePurchaseMethod.DayaLoan; + + // ثبت سفارش پکیج (فعلاً پکیج پایه) + var goldenPackage = await _context.Packages + .FirstOrDefaultAsync(p => p.Id==4, cancellationToken); + + if (goldenPackage != null) + { + // پیدا کردن آدرس پیش‌فرض کاربر + var defaultAddress = await _context.UserAddresses + .Where(a => a.UserId == request.UserId) + .OrderByDescending(a => a.Created) + .FirstOrDefaultAsync(cancellationToken); + + if (defaultAddress != null) + { + var packageOrder = new UserOrder + { + UserId = request.UserId, + PackageId = goldenPackage.Id, + Amount = request.WalletAmount, // 56 میلیون + PaymentStatus = PaymentStatus.Success, + PaymentDate = DateTime.Now, + DeliveryStatus = DeliveryStatus.None, + UserAddressId = defaultAddress.Id, + TransactionId = transaction.Id, + PaymentMethod = PaymentMethod.IPG + }; + + await _context.UserOrders.AddAsync(packageOrder, cancellationToken); + } + } + + // ثبت Event + user.AddDomainEvent(new DayaLoanApprovedEvent(user, transaction, request.ContractNumber)); + + // به‌روزرسانی DayaLoanContract.IsProcessed + var dayaContract = await _context.DayaLoanContracts + .FirstOrDefaultAsync(d => d.UserId == request.UserId || d.ContractNumber == request.ContractNumber, cancellationToken); + + if (dayaContract != null) + { + dayaContract.IsProcessed = true; + _logger.LogInformation("Marked DayaLoanContract as processed for User {UserId}", request.UserId); + } + + await _context.SaveChangesAsync(cancellationToken); + + // ارسال SMS به کاربر + await SendDayaLoanSmsAsync(user); + + return new ProcessDayaLoanApprovalResponseDto + { + UserId = user.Id, + TransactionId = transaction.Id, + ContractNumber = request.ContractNumber, + MainWalletBalance = wallet.Balance, + LockedWalletBalance = wallet.NetworkBalance, + DiscountWalletBalance = wallet.DiscountBalance, + Message = "اعتبار دایا با موفقیت دریافت شد" + }; + } + + /// + /// ارسال SMS اطلاع‌رسانی دریافت اعتبار دایا + /// + private async Task SendDayaLoanSmsAsync(User user) + { + try + { + var userName = SmsTemplates.GetUserName(user.FirstName); + var message = SmsTemplates.DayaLoanReceived(userName); + + await _smsService.SendAsync(user.Mobile, message); + + _logger.LogInformation( + "Daya loan SMS sent to User {UserId}, Mobile: {Mobile}", + user.Id, user.Mobile); + } + catch (Exception ex) + { + // خطای SMS نباید فرایند اصلی رو متوقف کنه + _logger.LogError(ex, + "Failed to send Daya loan SMS to User {UserId}, Mobile: {Mobile}", + user.Id, user.Mobile); + } + } +}