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:
@@ -45,7 +45,7 @@ public class CancelOrderCommandHandler : IRequestHandler<CancelOrderCommand, Can
|
||||
order.Transaction.PaymentStatus == PaymentStatus.Success)
|
||||
{
|
||||
// ایجاد تراکنش استرداد
|
||||
var refundTransaction = new Transactions
|
||||
var refundTransaction = new Transaction
|
||||
{
|
||||
Amount = -order.Amount,
|
||||
Description = $"بازگشت وجه سفارش {request.OrderId}: {request.CancelReason}",
|
||||
@@ -55,7 +55,7 @@ public class CancelOrderCommandHandler : IRequestHandler<CancelOrderCommand, Can
|
||||
Type = TransactionType.Buy
|
||||
};
|
||||
|
||||
await _context.Transactionss.AddAsync(refundTransaction, cancellationToken);
|
||||
await _context.Transactions.AddAsync(refundTransaction, cancellationToken);
|
||||
}
|
||||
|
||||
// ثبت Event
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ public class GetAllUserOrderByFilterQueryHandler : IRequestHandler<GetAllUserOrd
|
||||
var query = _context.UserOrders
|
||||
.Include(i => i.UserAddress)
|
||||
.Include(i => i.User)
|
||||
.Include(i => i.FactorDetailss)
|
||||
.Include(i => i.FactorDetails)
|
||||
.ThenInclude(t => t.Product)
|
||||
.ApplyOrder(sortBy: request.SortBy)
|
||||
.AsNoTracking()
|
||||
@@ -48,7 +48,7 @@ public class GetAllUserOrderByFilterQueryHandler : IRequestHandler<GetAllUserOrd
|
||||
UserAddressId = x.UserAddressId,
|
||||
PaymentMethod = x.PaymentMethod,
|
||||
UserAddressText = x.UserAddress.Address,
|
||||
FactorDetails = x.FactorDetailss.Select(fd => new GetAllUserOrderByFilterResponseModelFactorDetail
|
||||
FactorDetails = x.FactorDetails.Select(fd => new GetAllUserOrderByFilterResponseModelFactorDetail
|
||||
{
|
||||
ProductId = fd.ProductId,
|
||||
ProductTitle = fd.Product.Title,
|
||||
|
||||
@@ -14,7 +14,7 @@ public class GetUserOrderQueryHandler : IRequestHandler<GetUserOrderQuery, GetUs
|
||||
var response = await _context.UserOrders
|
||||
.Include(i => i.UserAddress)
|
||||
.Include(i => i.User)
|
||||
.Include(i => i.FactorDetailss)
|
||||
.Include(i => i.FactorDetails)
|
||||
.ThenInclude(t => t.Product)
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Id == request.Id)
|
||||
@@ -30,7 +30,7 @@ public class GetUserOrderQueryHandler : IRequestHandler<GetUserOrderQuery, GetUs
|
||||
UserAddressId = x.UserAddressId,
|
||||
PaymentMethod = x.PaymentMethod,
|
||||
UserAddressText = x.UserAddress.Address,
|
||||
FactorDetails = x.FactorDetailss.Select(fd => new GetUserOrderResponseFactorDetail
|
||||
FactorDetails = x.FactorDetails.Select(fd => new GetUserOrderResponseFactorDetail
|
||||
{
|
||||
ProductId = fd.ProductId,
|
||||
ProductTitle = fd.Product.Title,
|
||||
|
||||
Reference in New Issue
Block a user