feat: implement unified command for Daya loan status check and processing - Refactored DayaLoanCheckWorker to use CheckAndProcessDayaLoansCommand, enhancing functionality and logging
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 1m50s
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 1m50s
This commit is contained in:
+15
@@ -0,0 +1,15 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.DayaLoanCQ.Commands.CheckAndProcessDayaLoans;
|
||||
|
||||
/// <summary>
|
||||
/// Command یکپارچه برای استعلام وضعیت وام از سرویس دایا و پردازش خودکار وامهای تأیید شده
|
||||
/// این Command هم استعلام میکند و هم در صورت تأیید، کیف پول را شارژ میکند
|
||||
/// </summary>
|
||||
public record CheckAndProcessDayaLoansCommand : IRequest<CheckAndProcessDayaLoansResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// لیست کدهای ملی برای استعلام
|
||||
/// </summary>
|
||||
public required List<string> NationalCodes { get; init; }
|
||||
}
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
using CMSMicroservice.Domain.Events;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using CMSMicroservice.Application.DayaLoanCQ.Services;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CMSMicroservice.Application.DayaLoanCQ.Commands.CheckAndProcessDayaLoans;
|
||||
|
||||
/// <summary>
|
||||
/// Handler یکپارچه برای استعلام و پردازش وام دایا
|
||||
/// 1. استعلام از API دایا
|
||||
/// 2. ذخیره/بهروزرسانی DayaLoanContract
|
||||
/// 3. شارژ کیف پول برای وامهای تأیید شده
|
||||
/// 4. ثبت Order پکیج طلایی
|
||||
/// 5. ارسال SMS
|
||||
/// </summary>
|
||||
public class CheckAndProcessDayaLoansCommandHandler : IRequestHandler<CheckAndProcessDayaLoansCommand, CheckAndProcessDayaLoansResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly IDayaLoanApiService _dayaApiService;
|
||||
private readonly IKavenegarService _smsService;
|
||||
private readonly ILogger<CheckAndProcessDayaLoansCommandHandler> _logger;
|
||||
|
||||
public CheckAndProcessDayaLoansCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
IDayaLoanApiService dayaApiService,
|
||||
IKavenegarService smsService,
|
||||
ILogger<CheckAndProcessDayaLoansCommandHandler> logger)
|
||||
{
|
||||
_context = context;
|
||||
_dayaApiService = dayaApiService;
|
||||
_smsService = smsService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<CheckAndProcessDayaLoansResponseDto> Handle(CheckAndProcessDayaLoansCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var results = new List<DayaLoanProcessResult>();
|
||||
var processedCount = 0;
|
||||
|
||||
try
|
||||
{
|
||||
// 1. استعلام از سرویس دایا
|
||||
_logger.LogInformation("Checking Daya loan status for {Count} national codes", request.NationalCodes.Count);
|
||||
var dayaResults = await _dayaApiService.CheckLoanStatusAsync(request.NationalCodes, cancellationToken);
|
||||
|
||||
foreach (var dayaResult in dayaResults)
|
||||
{
|
||||
var result = new DayaLoanProcessResult
|
||||
{
|
||||
NationalCode = dayaResult.NationalCode,
|
||||
Status = dayaResult.Status,
|
||||
ContractNumber = dayaResult.ContractNumber,
|
||||
WasProcessed = false,
|
||||
Message = "استعلام موفق"
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// 2. پیدا کردن کاربر
|
||||
var user = await _context.Users
|
||||
.Include(u => u.UserWallets)
|
||||
.FirstOrDefaultAsync(u => u.NationalCode == dayaResult.NationalCode, cancellationToken);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
result.Message = "کاربر یافت نشد";
|
||||
results.Add(result);
|
||||
continue;
|
||||
}
|
||||
|
||||
result.UserId = user.Id;
|
||||
|
||||
// 3. ذخیره/بهروزرسانی DayaLoanContract
|
||||
var contract = await _context.DayaLoanContracts
|
||||
.FirstOrDefaultAsync(d => d.NationalCode == dayaResult.NationalCode, cancellationToken);
|
||||
|
||||
if (contract == null)
|
||||
{
|
||||
contract = new DayaLoanContract
|
||||
{
|
||||
UserId = user.Id,
|
||||
NationalCode = dayaResult.NationalCode,
|
||||
Status = dayaResult.Status,
|
||||
ContractNumber = dayaResult.ContractNumber,
|
||||
LastCheckDate = DateTime.Now,
|
||||
IsProcessed = false
|
||||
};
|
||||
await _context.DayaLoanContracts.AddAsync(contract, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
contract.Status = dayaResult.Status;
|
||||
contract.ContractNumber = dayaResult.ContractNumber;
|
||||
contract.LastCheckDate = DateTime.Now;
|
||||
}
|
||||
|
||||
// 4. آیا باید پردازش مالی انجام شود؟
|
||||
var shouldProcess = !contract.IsProcessed &&
|
||||
!user.HasReceivedDayaCredit &&
|
||||
!string.IsNullOrEmpty(dayaResult.ContractNumber) &&
|
||||
(dayaResult.Status == DayaLoanStatus.PendingReceive ||
|
||||
dayaResult.Status == DayaLoanStatus.Received);
|
||||
|
||||
if (shouldProcess)
|
||||
{
|
||||
// 5. پردازش مالی
|
||||
var processResult = await ProcessDayaLoanAsync(user, dayaResult.ContractNumber!, cancellationToken);
|
||||
|
||||
contract.IsProcessed = true;
|
||||
result.WasProcessed = true;
|
||||
result.NewWalletBalance = processResult.NewBalance;
|
||||
result.Message = "وام پردازش و کیف پول شارژ شد";
|
||||
processedCount++;
|
||||
|
||||
_logger.LogInformation(
|
||||
"Daya loan processed for User {UserId}, Contract: {ContractNumber}, NewBalance: {Balance}",
|
||||
user.Id, dayaResult.ContractNumber, processResult.NewBalance);
|
||||
}
|
||||
else if (contract.IsProcessed || user.HasReceivedDayaCredit)
|
||||
{
|
||||
result.Message = "قبلاً پردازش شده";
|
||||
}
|
||||
else if (string.IsNullOrEmpty(dayaResult.ContractNumber))
|
||||
{
|
||||
result.Message = "هنوز قرارداد ندارد";
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error processing Daya loan for NationalCode {NationalCode}", dayaResult.NationalCode);
|
||||
result.Message = $"خطا: {ex.Message}";
|
||||
}
|
||||
|
||||
results.Add(result);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error calling Daya API service");
|
||||
|
||||
// در صورت خطا در API
|
||||
foreach (var nationalCode in request.NationalCodes)
|
||||
{
|
||||
if (!results.Any(r => r.NationalCode == nationalCode))
|
||||
{
|
||||
results.Add(new DayaLoanProcessResult
|
||||
{
|
||||
NationalCode = nationalCode,
|
||||
Status = DayaLoanStatus.PendingReceive,
|
||||
WasProcessed = false,
|
||||
Message = $"خطا در استعلام: {ex.Message}"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new CheckAndProcessDayaLoansResponseDto
|
||||
{
|
||||
Results = results,
|
||||
TotalChecked = request.NationalCodes.Count,
|
||||
WithContractCount = results.Count(r => !string.IsNullOrEmpty(r.ContractNumber)),
|
||||
ProcessedCount = processedCount
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// پردازش مالی وام دایا
|
||||
/// </summary>
|
||||
private async Task<(long NewBalance, long TransactionId)> ProcessDayaLoanAsync(
|
||||
User user,
|
||||
string contractNumber,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// 1. ایجاد تراکنش
|
||||
var transaction = new Transaction
|
||||
{
|
||||
Amount = SystemConstants.DayaLoanAmount,
|
||||
Description = $"دریافت اعتبار دایا - قرارداد {contractNumber}",
|
||||
PaymentStatus = PaymentStatus.Success,
|
||||
PaymentDate = DateTime.Now,
|
||||
RefId = contractNumber,
|
||||
Type = TransactionType.DepositExternal1
|
||||
};
|
||||
|
||||
await _context.Transactions.AddAsync(transaction, cancellationToken);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// 2. یافتن یا ایجاد کیف پول
|
||||
var wallet = user.UserWallets.FirstOrDefault();
|
||||
if (wallet == null)
|
||||
{
|
||||
wallet = new UserWallet
|
||||
{
|
||||
UserId = user.Id,
|
||||
Balance = 0,
|
||||
NetworkBalance = 0,
|
||||
DiscountBalance = 0
|
||||
};
|
||||
await _context.UserWallets.AddAsync(wallet, cancellationToken);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
// 3. شارژ کیف پول عادی
|
||||
wallet.Balance += SystemConstants.DayaLoanAmount;
|
||||
|
||||
var mainLog = new UserWalletChangeLog
|
||||
{
|
||||
WalletId = wallet.Id,
|
||||
CurrentBalance = wallet.Balance,
|
||||
ChangeValue = SystemConstants.DayaLoanAmount,
|
||||
CurrentNetworkBalance = wallet.NetworkBalance,
|
||||
ChangeNerworkValue = 0,
|
||||
IsIncrease = true,
|
||||
RefrenceId = transaction.Id
|
||||
};
|
||||
await _context.UserWalletChangeLogs.AddAsync(mainLog, cancellationToken);
|
||||
|
||||
// 4. شارژ کیف پول تخفیف (دو برابر)
|
||||
var discountAmount = SystemConstants.DayaLoanAmount * 2;
|
||||
wallet.DiscountBalance += discountAmount;
|
||||
|
||||
var discountLog = new UserWalletChangeLog
|
||||
{
|
||||
WalletId = wallet.Id,
|
||||
CurrentBalance = wallet.Balance,
|
||||
ChangeValue = 0,
|
||||
CurrentNetworkBalance = wallet.NetworkBalance,
|
||||
ChangeNerworkValue = 0,
|
||||
CurrentDiscountBalance = wallet.DiscountBalance,
|
||||
ChangeDiscountValue = discountAmount,
|
||||
IsIncrease = true,
|
||||
RefrenceId = transaction.Id
|
||||
};
|
||||
await _context.UserWalletChangeLogs.AddAsync(discountLog, cancellationToken);
|
||||
|
||||
// 5. بهروزرسانی کاربر
|
||||
user.HasReceivedDayaCredit = true;
|
||||
user.DayaCreditReceivedAt = DateTime.Now;
|
||||
user.PackagePurchaseMethod = PackagePurchaseMethod.DayaLoan;
|
||||
|
||||
// 6. ثبت Order پکیج پایه
|
||||
var goldenPackage = await _context.Packages
|
||||
.FirstOrDefaultAsync(p => p.Id == 4, cancellationToken);
|
||||
|
||||
if (goldenPackage != null)
|
||||
{
|
||||
// 6. ثبت UserPackagePurchase برای پکیج پایه
|
||||
var goldenPackageId =goldenPackage.Id;
|
||||
var packagePurchase = new UserPackagePurchase
|
||||
{
|
||||
UserId = user.Id,
|
||||
PackageId = goldenPackageId,
|
||||
PurchaseMethod = PackagePurchaseMethod.DayaLoan,
|
||||
PurchasedAt = DateTime.Now,
|
||||
Amount = SystemConstants.DayaLoanAmount,
|
||||
TransactionId = transaction.Id
|
||||
};
|
||||
|
||||
await _context.UserPackagePurchases.AddAsync(packagePurchase, cancellationToken);
|
||||
|
||||
}
|
||||
|
||||
// 7. Domain Event
|
||||
user.AddDomainEvent(new DayaLoanApprovedEvent(user, transaction, contractNumber));
|
||||
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// 8. ارسال SMS
|
||||
await SendDayaLoanSmsAsync(user);
|
||||
|
||||
return (wallet.Balance, transaction.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ارسال SMS اطلاعرسانی
|
||||
/// </summary>
|
||||
private async Task SendDayaLoanSmsAsync(User user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userName = SmsTemplates.GetUserName(user.FirstName+" "+user.LastName);
|
||||
var message = SmsTemplates.DayaLoanReceived(userName);
|
||||
|
||||
await _smsService.SendAsync(user.Mobile, message);
|
||||
|
||||
// ارسال SMS به ادمین برای اطلاع
|
||||
var adminMessage = $"وام دایا دریافت شد\nکاربر: {user.FirstName} {user.LastName}\nموبایل: {user.Mobile}\nکدملی: {user.NationalCode}";
|
||||
await _smsService.SendAsync("09199877503", adminMessage);
|
||||
|
||||
_logger.LogInformation("Daya loan SMS sent to User {UserId}", user.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to send Daya loan SMS to User {UserId}", user.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.DayaLoanCQ.Commands.CheckAndProcessDayaLoans;
|
||||
|
||||
/// <summary>
|
||||
/// پاسخ Command استعلام و پردازش وام دایا
|
||||
/// </summary>
|
||||
public class CheckAndProcessDayaLoansResponseDto
|
||||
{
|
||||
/// <summary>
|
||||
/// نتایج استعلام و پردازش
|
||||
/// </summary>
|
||||
public required List<DayaLoanProcessResult> Results { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تعداد کل استعلام شده
|
||||
/// </summary>
|
||||
public int TotalChecked { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تعداد موفق (دارای قرارداد)
|
||||
/// </summary>
|
||||
public int WithContractCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تعداد پردازش شده (شارژ کیف پول)
|
||||
/// </summary>
|
||||
public int ProcessedCount { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// نتیجه پردازش هر کاربر
|
||||
/// </summary>
|
||||
public class DayaLoanProcessResult
|
||||
{
|
||||
/// <summary>
|
||||
/// کد ملی
|
||||
/// </summary>
|
||||
public required string NationalCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// شناسه کاربر
|
||||
/// </summary>
|
||||
public long? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// وضعیت وام در دایا
|
||||
/// </summary>
|
||||
public DayaLoanStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// شماره قرارداد
|
||||
/// </summary>
|
||||
public string? ContractNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// آیا پردازش مالی انجام شد؟
|
||||
/// </summary>
|
||||
public bool WasProcessed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// موجودی کیف پول بعد از شارژ
|
||||
/// </summary>
|
||||
public long? NewWalletBalance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// پیام
|
||||
/// </summary>
|
||||
public required string Message { get; set; }
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.DayaLoanCQ.Commands.CheckDayaLoanStatus;
|
||||
|
||||
/// <summary>
|
||||
/// Command برای استعلام وضعیت وام از سرویس دایا
|
||||
/// </summary>
|
||||
public record CheckDayaLoanStatusCommand : IRequest<CheckDayaLoanStatusResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// لیست کدهای ملی برای استعلام
|
||||
/// </summary>
|
||||
public List<string> NationalCodes { get; init; }
|
||||
}
|
||||
-235
@@ -1,235 +0,0 @@
|
||||
using CMSMicroservice.Domain.Events;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using CMSMicroservice.Application.DayaLoanCQ.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CMSMicroservice.Application.DayaLoanCQ.Commands.CheckDayaLoanStatus;
|
||||
|
||||
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)
|
||||
{
|
||||
var previousStatus = existingContract.Status;
|
||||
existingContract.LastCheckDate = DateTime.Now;
|
||||
existingContract.Status = dayaResult.Status;
|
||||
existingContract.ContractNumber = dayaResult.ContractNumber;
|
||||
|
||||
// بررسی تغییر وضعیت به PendingReceive یا Received
|
||||
// فقط اگر قبلاً پردازش نشده باشد
|
||||
if (!existingContract.IsProcessed &&
|
||||
!string.IsNullOrEmpty(dayaResult.ContractNumber) &&
|
||||
(dayaResult.Status == DayaLoanStatus.PendingReceive || dayaResult.Status == DayaLoanStatus.Received))
|
||||
{
|
||||
await ProcessDayaLoanReceivedAsync(existingContract.UserId, dayaResult.ContractNumber, cancellationToken);
|
||||
existingContract.IsProcessed = true;
|
||||
|
||||
_logger.LogInformation(
|
||||
"Daya loan processed for User {UserId}, ContractNumber: {ContractNumber}, Amount: {Amount}",
|
||||
existingContract.UserId, dayaResult.ContractNumber, SystemConstants.DayaLoanAmount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var user = await _context.Users
|
||||
.FirstOrDefaultAsync(u => u.NationalCode == dayaResult.NationalCode, cancellationToken);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
var isProcessed = false;
|
||||
|
||||
// اگر وضعیت PendingReceive یا Received بود و قرارداد دارد، فوری پردازش کن
|
||||
if (!string.IsNullOrEmpty(dayaResult.ContractNumber) &&
|
||||
(dayaResult.Status == DayaLoanStatus.PendingReceive || dayaResult.Status == DayaLoanStatus.Received))
|
||||
{
|
||||
await ProcessDayaLoanReceivedAsync(user.Id, dayaResult.ContractNumber, cancellationToken);
|
||||
isProcessed = true;
|
||||
|
||||
_logger.LogInformation(
|
||||
"Daya loan processed for new contract - User {UserId}, ContractNumber: {ContractNumber}, Amount: {Amount}",
|
||||
user.Id, dayaResult.ContractNumber, SystemConstants.DayaLoanAmount);
|
||||
}
|
||||
|
||||
var newContract = new DayaLoanContract
|
||||
{
|
||||
UserId = user.Id,
|
||||
NationalCode = dayaResult.NationalCode,
|
||||
Status = dayaResult.Status,
|
||||
ContractNumber = dayaResult.ContractNumber,
|
||||
LastCheckDate = DateTime.Now,
|
||||
IsProcessed = isProcessed
|
||||
};
|
||||
|
||||
await _context.DayaLoanContracts.AddAsync(newContract, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// پردازش دریافت وام دایا برای کاربر
|
||||
/// 1. شارژ کیف پول (Balance + DiscountBalance)
|
||||
/// 2. ثبت تراکنش
|
||||
/// 3. ثبت لاگ کیف پول
|
||||
/// 4. بهروزرسانی وضعیت کاربر
|
||||
/// </summary>
|
||||
private async Task ProcessDayaLoanReceivedAsync(long userId, string contractNumber, CancellationToken cancellationToken)
|
||||
{
|
||||
// پیدا کردن کاربر
|
||||
var user = await _context.Users
|
||||
.FirstOrDefaultAsync(u => u.Id == userId, cancellationToken);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
_logger.LogWarning("User {UserId} not found for Daya loan processing", userId);
|
||||
return;
|
||||
}
|
||||
|
||||
// بررسی اینکه قبلاً دریافت نکرده باشد
|
||||
if (user.HasReceivedDayaCredit)
|
||||
{
|
||||
_logger.LogWarning("User {UserId} has already received Daya credit", userId);
|
||||
return;
|
||||
}
|
||||
|
||||
// پیدا کردن یا ایجاد کیف پول کاربر
|
||||
var wallet = await _context.UserWallets
|
||||
.FirstOrDefaultAsync(w => w.UserId == userId, cancellationToken);
|
||||
|
||||
if (wallet == null)
|
||||
{
|
||||
wallet = new UserWallet
|
||||
{
|
||||
UserId = userId,
|
||||
Balance = 0,
|
||||
NetworkBalance = 0,
|
||||
DiscountBalance = 0
|
||||
};
|
||||
await _context.UserWallets.AddAsync(wallet, cancellationToken);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
// 1. شارژ کیف پول - هم موجودی اصلی و هم موجودی تخفیف
|
||||
var previousBalance = wallet.Balance;
|
||||
var previousDiscountBalance = wallet.DiscountBalance;
|
||||
|
||||
wallet.Balance += SystemConstants.DayaLoanAmount;
|
||||
wallet.DiscountBalance += SystemConstants.DayaLoanAmount;
|
||||
|
||||
// 2. ثبت تراکنش - RefId = شماره قرارداد، Status = 0 (Success)، Type = 2 (DepositExternal1)
|
||||
var transaction = new Transaction
|
||||
{
|
||||
Amount = SystemConstants.DayaLoanAmount,
|
||||
Description = $"شارژ کیف پول از وام دایا - قرارداد {contractNumber}",
|
||||
PaymentStatus = PaymentStatus.Success, // 0
|
||||
PaymentDate = DateTime.Now,
|
||||
RefId = contractNumber,
|
||||
Type = TransactionType.DepositExternal1 // 2
|
||||
};
|
||||
|
||||
await _context.Transactions.AddAsync(transaction, cancellationToken);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// 3. ثبت لاگ کیف پول با شناسه تراکنش
|
||||
var walletLog = new UserWalletChangeLog
|
||||
{
|
||||
WalletId = wallet.Id,
|
||||
CurrentBalance = wallet.Balance,
|
||||
ChangeValue = SystemConstants.DayaLoanAmount,
|
||||
CurrentNetworkBalance = wallet.NetworkBalance,
|
||||
ChangeNerworkValue = 0,
|
||||
CurrentDiscountBalance = wallet.DiscountBalance,
|
||||
ChangeDiscountValue = SystemConstants.DayaLoanAmount,
|
||||
IsIncrease = true,
|
||||
RefrenceId = transaction.Id
|
||||
};
|
||||
|
||||
await _context.UserWalletChangeLogs.AddAsync(walletLog, cancellationToken);
|
||||
|
||||
// 4. بهروزرسانی وضعیت کاربر
|
||||
user.HasReceivedDayaCredit = true;
|
||||
user.DayaCreditReceivedAt = DateTime.Now;
|
||||
user.PackagePurchaseMethod = PackagePurchaseMethod.DayaLoan; // 1
|
||||
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
_logger.LogInformation(
|
||||
"Daya loan fully processed for User {UserId}: " +
|
||||
"Wallet Balance {PreviousBalance} -> {NewBalance}, " +
|
||||
"DiscountBalance {PreviousDiscountBalance} -> {NewDiscountBalance}, " +
|
||||
"Transaction Id: {TransactionId}",
|
||||
userId, previousBalance, wallet.Balance,
|
||||
previousDiscountBalance, wallet.DiscountBalance,
|
||||
transaction.Id);
|
||||
}
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.DayaLoanCQ.Commands.CheckDayaLoanStatus;
|
||||
|
||||
public class CheckDayaLoanStatusResponseDto
|
||||
{
|
||||
public List<DayaLoanStatusItem> Results { get; set; }
|
||||
public int TotalChecked { get; set; }
|
||||
public int SuccessCount { get; set; }
|
||||
}
|
||||
|
||||
public class DayaLoanStatusItem
|
||||
{
|
||||
public string NationalCode { get; set; }
|
||||
public DayaLoanStatus Status { get; set; }
|
||||
public string? ContractNumber { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using CMSMicroservice.Domain.Common;
|
||||
|
||||
namespace CMSMicroservice.Application.DayaLoanCQ.Commands.ProcessDayaLoanApproval;
|
||||
|
||||
/// <summary>
|
||||
/// Command برای پردازش تایید وام دایا و شارژ کیف پول
|
||||
/// </summary>
|
||||
public record ProcessDayaLoanApprovalCommand : IRequest<ProcessDayaLoanApprovalResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه کاربر
|
||||
/// </summary>
|
||||
public long UserId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// شماره قرارداد دایا
|
||||
/// </summary>
|
||||
public string ContractNumber { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ کیف پول عادی
|
||||
/// </summary>
|
||||
public long WalletAmount { get; init; } = SystemConstants.DayaLoanAmount;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ کیف پول تخفیف (دو برابر)
|
||||
/// </summary>
|
||||
public long DiscountWalletAmount { get; init; } = SystemConstants.DayaLoanAmount * 2;
|
||||
}
|
||||
-192
@@ -1,192 +0,0 @@
|
||||
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));
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
namespace CMSMicroservice.Application.DayaLoanCQ.Commands.ProcessDayaLoanApproval;
|
||||
|
||||
public class ProcessDayaLoanApprovalCommandValidator : AbstractValidator<ProcessDayaLoanApprovalCommand>
|
||||
{
|
||||
public ProcessDayaLoanApprovalCommandValidator()
|
||||
{
|
||||
RuleFor(v => v.UserId)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("شناسه کاربر باید بزرگتر از صفر باشد");
|
||||
|
||||
RuleFor(v => v.ContractNumber)
|
||||
.NotEmpty()
|
||||
.WithMessage("شماره قرارداد الزامی است")
|
||||
.MaximumLength(100)
|
||||
.WithMessage("شماره قرارداد نباید بیش از 100 کاراکتر باشد");
|
||||
|
||||
RuleFor(v => v.WalletAmount)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("مبلغ کیف پول باید بزرگتر از صفر باشد");
|
||||
}
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
namespace CMSMicroservice.Application.DayaLoanCQ.Commands.ProcessDayaLoanApproval;
|
||||
|
||||
public class ProcessDayaLoanApprovalResponseDto
|
||||
{
|
||||
public long UserId { get; set; }
|
||||
public long TransactionId { get; set; }
|
||||
public string ContractNumber { get; set; }
|
||||
public long MainWalletBalance { get; set; }
|
||||
public long LockedWalletBalance { get; set; }
|
||||
public long DiscountWalletBalance { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user