Files
CMS/src/CMSMicroservice.Application/UserOrderCQ/Commands/SubmitShopBuyOrder/SubmitShopBuyOrderCommandHandler.cs
T
masoodafar-web 02e2f8111f
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 1m38s
feat: implement Kavenegar SMS service and refactor system configurations to use static constants
2025-12-26 09:04:27 +03:30

229 lines
8.8 KiB
C#

using CMSMicroservice.Domain.Common;
using CMSMicroservice.Domain.Enums;
using CMSMicroservice.Domain.Events;
using CMSMicroservice.Domain.Entities.Order;
using Microsoft.Extensions.Logging;
namespace CMSMicroservice.Application.UserOrderCQ.Commands.SubmitShopBuyOrder;
public class
SubmitShopBuyOrderCommandHandler : IRequestHandler<SubmitShopBuyOrderCommand, SubmitShopBuyOrderResponseDto>
{
private readonly IApplicationDbContext _context;
private readonly ILogger<SubmitShopBuyOrderCommandHandler> _logger;
private float _vatRate;
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.UserAddresses)
.Include(i => i.UserWallets)
.ThenInclude(i => i.UserWalletChangeLogs)
.Include(i => i.UserCarts)
.ThenInclude(i => i.Product)
.FirstOrDefaultAsync(w => w.Id == request.UserId, cancellationToken: cancellationToken);
if (user.UserCarts.Count == 0)
throw new NotFoundException("UserCart", request.UserId);
// چک موجودی محصولات
var outOfStockProducts = new List<string>();
var insufficientStockProducts = new List<(string Title, int Requested, int Available)>();
foreach (var cartItem in user.UserCarts)
{
if (cartItem.Product.RemainingCount <= 0)
{
outOfStockProducts.Add(cartItem.Product.Title);
}
else if (cartItem.Product.RemainingCount < cartItem.Count)
{
insufficientStockProducts.Add((cartItem.Product.Title, cartItem.Count,
cartItem.Product.RemainingCount));
}
}
if (outOfStockProducts.Any())
{
throw new Exception($"محصولات زیر ناموجود شده‌اند: {string.Join("، ", outOfStockProducts)}");
}
if (insufficientStockProducts.Any())
{
var messages = insufficientStockProducts.Select(p =>
$"«{p.Title}»: درخواست {p.Requested} عدد، موجودی {p.Available} عدد");
throw new Exception($"موجودی محصولات زیر کافی نیست: {string.Join(" | ", messages)}");
}
long finalAmount = 0;
// استفاده از SystemConstants برای VAT
if (SystemConstants.ShopVATEnabled)
{
_vatRate = (float)SystemConstants.ShopVAT;
finalAmount = AddVAT(user.UserCarts.Sum(s => s.Count * s.Product.Price));
_logger.LogInformation(
"Calculating final amount with VAT. Base Amount: {BaseAmount}, VAT Rate: {VATRate}, Final Amount: {FinalAmount}",
user.UserCarts.Sum(s => s.Count * s.Product.Price), _vatRate, finalAmount);
}
else
{
finalAmount = user.UserCarts.Sum(s => s.Count * s.Product.Price);
}
if (finalAmount != request.TotalAmount)
throw new Exception("مبلغ سفارش با مجموع سبد خرید مطابقت ندارد.");
var userWallet = user.UserWallets.FirstOrDefault();
if (userWallet == null)
throw new Exception("کیف پول کاربر یافت نشد.");
if (userWallet.Balance <= 0 || userWallet.Balance < request.TotalAmount)
throw new Exception("موجودی کیف پول کاربر برای انجام این تراکنش کافی نیست.");
var newTransaction = new Transaction()
{
Amount = request.TotalAmount,
Description = "خرید از فروشگاه",
PaymentStatus = PaymentStatus.Success,
PaymentDate = DateTime.Now,
Type = TransactionType.Buy,
RefId = "localwallet-" + Guid.NewGuid().ToString()
};
await _context.Transactions.AddAsync(newTransaction, cancellationToken);
await _context.SaveChangesAsync(cancellationToken);
var newWalletLog = new UserWalletChangeLog()
{
CurrentBalance = userWallet.Balance,
CurrentNetworkBalance = userWallet.NetworkBalance,
WalletId = userWallet.Id,
ChangeValue = -1 * request.TotalAmount,
IsIncrease = false,
RefrenceId = newTransaction.Id,
};
userWallet.Balance -= request.TotalAmount;
await _context.UserWalletChangeLogs.AddAsync(newWalletLog, cancellationToken);
await _context.SaveChangesAsync(cancellationToken);
var newOrder = new UserOrder()
{
Amount = request.TotalAmount,
PaymentStatus = PaymentStatus.Success,
PaymentMethod = PaymentMethod.Wallet,
PaymentDate = DateTime.Now,
UserId = request.UserId,
UserAddressId = user.UserAddresses.First(f => f.IsDefault).Id,
TransactionId = newTransaction.Id,
// سفارش فروشگاهی فیزیکی است، پس در ابتدا در انتظار ارسال است
DeliveryStatus = DeliveryStatus.Pending
};
await _context.UserOrders.AddAsync(newOrder, cancellationToken);
await _context.SaveChangesAsync(cancellationToken);
// محاسبه و ثبت 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 = SystemConstants.ShopVATEnabled ? AddVAT(s.Product.Price) : s.Product.Price,
OrderId = newOrder.Id
});
await _context.FactorDetails.AddRangeAsync(factorDetailsList, cancellationToken);
// کاهش موجودی محصولات و افزایش تعداد فروش
foreach (var cartItem in user.UserCarts)
{
cartItem.Product.RemainingCount -= cartItem.Count;
cartItem.Product.SaleCount += cartItem.Count;
}
user.UserCarts.Clear();
await _context.SaveChangesAsync(cancellationToken);
_logger.LogInformation("Order {OrderId} completed. Stock updated for {ProductCount} products.",
newOrder.Id, factorDetailsList.Count());
var finalResult = new SubmitShopBuyOrderResponseDto()
{
Id = newOrder.Id,
};
return finalResult;
}
public long CalculateVAT(long amount) => (long)(amount * _vatRate);
/// <summary>
/// محاسبه قیمت با احتساب مالیات
/// </summary>
public long AddVAT(long amount) => amount + CalculateVAT(amount);
private async Task<bool> CalculateAndSaveVAT(long orderId, long orderAmount, CancellationToken cancellationToken)
{
try
{
// بررسی فعال بودن VAT از SystemConstants
if (!SystemConstants.ShopVATEnabled)
{
_logger.LogInformation("VAT is disabled. Skipping VAT calculation for order {OrderId}", orderId);
return false;
}
// دریافت نرخ VAT از SystemConstants
var vatRate = SystemConstants.ShopVAT;
// محاسبه مالیات
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.Now
};
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;
}
}
}