feat: implement CheckDayaLoanStatusCommandHandler - Added handler for checking Daya loan status and updating contracts, including error handling and logging
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 1m10s
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 1m10s
This commit is contained in:
+121
@@ -0,0 +1,121 @@
|
|||||||
|
using CMSMicroservice.Domain.Enums;
|
||||||
|
using CMSMicroservice.Application.DayaLoanCQ.Services;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace CMSMicroservice.Application.DayaLoanCQ.Commands.CheckDayaLoanStatus;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// این Handler فقط وظیفه استعلام از API دایا و بهروزرسانی DayaLoanContracts را دارد.
|
||||||
|
/// پردازش مالی (شارژ کیف پول، ثبت Order و...) توسط Worker و ProcessDayaLoanApprovalCommand انجام میشود.
|
||||||
|
/// </summary>
|
||||||
|
public class CheckDayaLoanStatusCommandHandler : IRequestHandler<CheckDayaLoanStatusCommand, CheckDayaLoanStatusResponseDto>
|
||||||
|
{
|
||||||
|
private readonly IApplicationDbContext _context;
|
||||||
|
private readonly IDayaLoanApiService _dayaApiService;
|
||||||
|
private readonly ILogger<CheckDayaLoanStatusCommandHandler> _logger;
|
||||||
|
|
||||||
|
public CheckDayaLoanStatusCommandHandler(
|
||||||
|
IApplicationDbContext context,
|
||||||
|
IDayaLoanApiService dayaApiService,
|
||||||
|
ILogger<CheckDayaLoanStatusCommandHandler> logger)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_dayaApiService = dayaApiService;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<CheckDayaLoanStatusResponseDto> Handle(CheckDayaLoanStatusCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var results = new List<DayaLoanStatusItem>();
|
||||||
|
|
||||||
|
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)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+202
@@ -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<ProcessDayaLoanApprovalCommand, ProcessDayaLoanApprovalResponseDto>
|
||||||
|
{
|
||||||
|
private readonly IApplicationDbContext _context;
|
||||||
|
private readonly IKavenegarService _smsService;
|
||||||
|
private readonly ILogger<ProcessDayaLoanApprovalCommandHandler> _logger;
|
||||||
|
|
||||||
|
public ProcessDayaLoanApprovalCommandHandler(
|
||||||
|
IApplicationDbContext context,
|
||||||
|
IKavenegarService smsService,
|
||||||
|
ILogger<ProcessDayaLoanApprovalCommandHandler> logger)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_smsService = smsService;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ProcessDayaLoanApprovalResponseDto> 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 = "اعتبار دایا با موفقیت دریافت شد"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ارسال SMS اطلاعرسانی دریافت اعتبار دایا
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user