Add validators and services for Product Galleries and Product Tags

- Implemented Create, Delete, Get, and Update validators for Product Galleries.
- Added Create, Delete, Get, and Update validators for Product Tags.
- Created service classes for handling Discount Categories, Discount Orders, Discount Products, Discount Shopping Cart, Product Categories, Product Galleries, and Product Tags.
- Each service class integrates with CQRS for command and query handling.
- Established mapping profiles for Product Galleries.
This commit is contained in:
masoodafar-web
2025-12-04 02:40:49 +03:30
parent 40d54d08fc
commit f0f48118e7
436 changed files with 33159 additions and 2005 deletions

View File

@@ -1,5 +1,7 @@
using CMSMicroservice.Domain.Enums;
using CMSMicroservice.Domain.Events;
using CMSMicroservice.Domain.Entities.Order;
using Microsoft.Extensions.Logging;
namespace CMSMicroservice.Application.UserOrderCQ.Commands.SubmitShopBuyOrder;
@@ -7,26 +9,30 @@ public class
SubmitShopBuyOrderCommandHandler : IRequestHandler<SubmitShopBuyOrderCommand, SubmitShopBuyOrderResponseDto>
{
private readonly IApplicationDbContext _context;
private readonly ILogger<SubmitShopBuyOrderCommandHandler> _logger;
public SubmitShopBuyOrderCommandHandler(IApplicationDbContext context)
public SubmitShopBuyOrderCommandHandler(
IApplicationDbContext context,
ILogger<SubmitShopBuyOrderCommandHandler> logger)
{
_context = context;
_logger = logger;
}
public async Task<SubmitShopBuyOrderResponseDto> Handle(SubmitShopBuyOrderCommand request,
CancellationToken cancellationToken)
{
var user = await _context.Users
.Include(i => i.UserAddresss)
.Include(i => i.UserAddresses)
.Include(i => i.UserWallets)
.ThenInclude(i => i.UserWalletChangeLogs)
.Include(i => i.UserCartss)
.Include(i => i.UserCarts)
.ThenInclude(i => i.Product)
.FirstOrDefaultAsync(w => w.Id == request.UserId, cancellationToken: cancellationToken);
if (user.UserCartss.Count == 0)
if (user.UserCarts.Count == 0)
throw new NotFoundException("UserCart", request.UserId);
if (user.UserCartss.Sum(s => s.Count * s.Product.Price) != request.TotalAmount)
if (user.UserCarts.Sum(s => s.Count * s.Product.Price) != request.TotalAmount)
throw new Exception("مبلغ سفارش با مجموع سبد خرید مطابقت ندارد.");
@@ -37,7 +43,7 @@ public class
if (userWallet.Balance<=0 || userWallet.Balance<request.TotalAmount)
throw new Exception("موجودی کیف پول کاربر برای انجام این تراکنش کافی نیست.");
var newTransaction = new Transactions()
var newTransaction = new Transaction()
{
Amount = request.TotalAmount,
Description = "خرید از فروشگاه",
@@ -46,7 +52,7 @@ public class
Type = TransactionType.Buy,
RefId = "localwallet-" + Guid.NewGuid().ToString()
};
await _context.Transactionss.AddAsync(newTransaction, cancellationToken);
await _context.Transactions.AddAsync(newTransaction, cancellationToken);
await _context.SaveChangesAsync(cancellationToken);
var newWalletLog = new UserWalletChangeLog()
@@ -70,22 +76,31 @@ public class
PaymentMethod = PaymentMethod.Wallet,
PaymentDate = DateTime.Now,
UserId = request.UserId,
UserAddressId = user.UserAddresss.First(f => f.IsDefault).Id,
UserAddressId = user.UserAddresses.First(f => f.IsDefault).Id,
TransactionId = newTransaction.Id,
// سفارش فروشگاهی فیزیکی است، پس در ابتدا در انتظار ارسال است
DeliveryStatus = DeliveryStatus.Pending
};
await _context.UserOrders.AddAsync(newOrder, cancellationToken);
await _context.SaveChangesAsync(cancellationToken);
var factorDetailsList = user.UserCartss.Select(s => new FactorDetails()
// محاسبه و ثبت VAT (اگر فعال باشد)
var vatCreated = await CalculateAndSaveVAT(newOrder.Id, request.TotalAmount, cancellationToken);
if (vatCreated)
{
newOrder.HasVAT = true;
await _context.SaveChangesAsync(cancellationToken);
}
var factorDetailsList = user.UserCarts.Select(s => new FactorDetails()
{
ProductId = s.ProductId,
Count = s.Count,
UnitPrice = s.Product.Price,
OrderId = newOrder.Id
});
await _context.FactorDetailss.AddRangeAsync(factorDetailsList, cancellationToken);
user.UserCartss.Clear();
await _context.FactorDetails.AddRangeAsync(factorDetailsList, cancellationToken);
user.UserCarts.Clear();
await _context.SaveChangesAsync(cancellationToken);
var finalResult = new SubmitShopBuyOrderResponseDto()
{
@@ -94,4 +109,66 @@ public class
};
return finalResult;
}
private async Task<bool> CalculateAndSaveVAT(long orderId, long orderAmount, CancellationToken cancellationToken)
{
try
{
// بررسی فعال بودن VAT
var vatEnabledConfig = await _context.SystemConfigurations
.FirstOrDefaultAsync(x => x.Scope == ConfigurationScope.VAT && x.Key == "IsEnabled", cancellationToken);
if (vatEnabledConfig == null || !bool.TryParse(vatEnabledConfig.Value, out var isEnabled) || !isEnabled)
{
_logger.LogInformation("VAT is disabled. Skipping VAT calculation for order {OrderId}", orderId);
return false;
}
// دریافت نرخ VAT
var vatRateConfig = await _context.SystemConfigurations
.FirstOrDefaultAsync(x => x.Scope == ConfigurationScope.VAT && x.Key == "Rate", cancellationToken);
if (vatRateConfig == null || !decimal.TryParse(vatRateConfig.Value, out var vatRate))
{
_logger.LogWarning("VAT Rate configuration not found or invalid. Using default 0.09");
vatRate = 0.09m;
}
// محاسبه مالیات
var vatAmount = (long)(orderAmount * vatRate);
var totalAmount = orderAmount + vatAmount;
// ثبت VAT
var orderVAT = new OrderVAT
{
OrderId = orderId,
VATRate = vatRate,
BaseAmount = orderAmount,
VATAmount = vatAmount,
TotalAmount = totalAmount,
IsPaid = true,
PaidAt = DateTime.UtcNow
};
await _context.OrderVATs.AddAsync(orderVAT, cancellationToken);
await _context.SaveChangesAsync(cancellationToken);
_logger.LogInformation(
"VAT calculated and saved for order {OrderId}. Rate: {Rate}%, Base: {Base}, VAT: {VAT}, Total: {Total}",
orderId,
vatRate * 100,
orderAmount,
vatAmount,
totalAmount
);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error calculating VAT for order {OrderId}", orderId);
// عدم محاسبه VAT نباید مانع ثبت سفارش شود
return false;
}
}
}