feat: Add ClearCart command and response, implement CancelOrder command with validation, and enhance DeliveryStatus and User models

This commit is contained in:
masoodafar-web
2025-12-02 03:30:36 +03:30
parent 25fc73ae28
commit 78606cc5cc
100 changed files with 12925 additions and 8137 deletions

View File

@@ -0,0 +1,14 @@
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; }
}

View File

@@ -0,0 +1,108 @@
using CMSMicroservice.Domain.Events;
using CMSMicroservice.Domain.Enums;
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)
{
existingContract.LastCheckDate = DateTime.UtcNow;
existingContract.Status = dayaResult.Status;
existingContract.ContractNumber = dayaResult.ContractNumber;
}
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.UtcNow,
IsProcessed = false
};
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)
};
}
}

View File

@@ -0,0 +1,18 @@
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; }
}

View File

@@ -0,0 +1,34 @@
using CMSMicroservice.Domain.Enums;
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>
/// مبلغ کیف پول عادی (56 میلیون)
/// </summary>
public long WalletAmount { get; init; } = 56_000_000;
/// <summary>
/// مبلغ کیف پول قفل شده (56 میلیون)
/// </summary>
public long LockedWalletAmount { get; init; } = 56_000_000;
/// <summary>
/// مبلغ کیف پول تخفیف (56 میلیون)
/// </summary>
public long DiscountWalletAmount { get; init; } = 56_000_000;
}

View File

@@ -0,0 +1,169 @@
using CMSMicroservice.Domain.Events;
using CMSMicroservice.Domain.Enums;
namespace CMSMicroservice.Application.DayaLoanCQ.Commands.ProcessDayaLoanApproval;
public class ProcessDayaLoanApprovalCommandHandler : IRequestHandler<ProcessDayaLoanApprovalCommand, ProcessDayaLoanApprovalResponseDto>
{
private readonly IApplicationDbContext _context;
public ProcessDayaLoanApprovalCommandHandler(IApplicationDbContext context)
{
_context = context;
}
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 Transactions
{
Amount = request.WalletAmount + request.LockedWalletAmount + request.DiscountWalletAmount, // 168 میلیون
Description = $"دریافت اعتبار دایا - قرارداد {request.ContractNumber}",
PaymentStatus = PaymentStatus.Success,
PaymentDate = DateTime.UtcNow,
RefId = request.ContractNumber, // شماره قرارداد دایا
Type = TransactionType.DepositExternal1
};
await _context.Transactionss.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 balanceBeforeLocked = wallet.NetworkBalance;
wallet.NetworkBalance += request.LockedWalletAmount;
// لاگ کیف پول شبکه
var networkLog = new UserWalletChangeLog
{
WalletId = wallet.Id,
CurrentBalance = wallet.Balance,
ChangeValue = 0,
CurrentNetworkBalance = wallet.NetworkBalance,
ChangeNerworkValue = request.LockedWalletAmount,
IsIncrease = true,
RefrenceId = transaction.Id
};
await _context.UserWalletChangeLogs.AddAsync(networkLog, 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.UtcNow;
// تنظیم نحوه خرید پکیج به DayaLoan
user.PackagePurchaseMethod = PackagePurchaseMethod.DayaLoan;
// ثبت سفارش پکیج طلایی
var goldenPackage = await _context.Packages
.FirstOrDefaultAsync(p => p.Title.Contains("طلایی") || p.Title.Contains("Golden"), cancellationToken);
if (goldenPackage != null)
{
// پیدا کردن آدرس پیش‌فرض کاربر
var defaultAddress = await _context.UserAddresss
.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.UtcNow,
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);
return new ProcessDayaLoanApprovalResponseDto
{
UserId = user.Id,
TransactionId = transaction.Id,
ContractNumber = request.ContractNumber,
MainWalletBalance = wallet.Balance,
LockedWalletBalance = wallet.NetworkBalance,
DiscountWalletBalance = wallet.DiscountBalance,
Message = "اعتبار دایا با موفقیت دریافت شد"
};
}
}

View File

@@ -0,0 +1,21 @@
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("مبلغ کیف پول باید بزرگتر از صفر باشد");
}
}

View File

@@ -0,0 +1,12 @@
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; }
}