187 lines
6.5 KiB
C#
187 lines
6.5 KiB
C#
using CMSMicroservice.Application.Common.Interfaces;
|
|
using CMSMicroservice.Application.Common.Services;
|
|
using CMSMicroservice.Domain.Entities.DiscountShop;
|
|
using CMSMicroservice.Domain.Entities.Payment;
|
|
using CMSMicroservice.Domain.Enums;
|
|
using MediatR;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace CMSMicroservice.Application.DiscountShopCQ.Commands.PlaceOrder;
|
|
|
|
public class PlaceOrderCommandHandler : IRequestHandler<PlaceOrderCommand, PlaceOrderResponseDto>
|
|
{
|
|
private readonly IApplicationDbContext _context;
|
|
private readonly IInventoryService _inventoryService;
|
|
|
|
public PlaceOrderCommandHandler(
|
|
IApplicationDbContext context,
|
|
IInventoryService inventoryService)
|
|
{
|
|
_context = context;
|
|
_inventoryService = inventoryService;
|
|
}
|
|
|
|
public async Task<PlaceOrderResponseDto> Handle(PlaceOrderCommand request, CancellationToken cancellationToken)
|
|
{
|
|
// Get user wallet
|
|
var userWallet = await _context.UserWallets
|
|
.FirstOrDefaultAsync(w => w.UserId == request.UserId, cancellationToken);
|
|
|
|
if (userWallet == null)
|
|
{
|
|
return new PlaceOrderResponseDto
|
|
{
|
|
Success = false,
|
|
Message = "کیف پول کاربر یافت نشد"
|
|
};
|
|
}
|
|
|
|
// Get cart items with products
|
|
var cartItems = await _context.DiscountShoppingCarts
|
|
.Where(c => c.UserId == request.UserId)
|
|
.Include(c => c.Product)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
if (!cartItems.Any())
|
|
{
|
|
return new PlaceOrderResponseDto
|
|
{
|
|
Success = false,
|
|
Message = "سبد خرید خالی است"
|
|
};
|
|
}
|
|
|
|
// Validate stock and calculate totals
|
|
long totalAmount = 0;
|
|
long totalDiscountAmount = 0;
|
|
var orderDetails = new List<DiscountOrderDetail>();
|
|
|
|
foreach (var cartItem in cartItems)
|
|
{
|
|
var product = cartItem.Product;
|
|
|
|
// Check stock
|
|
if (product.RemainingCount < cartItem.Count)
|
|
{
|
|
return new PlaceOrderResponseDto
|
|
{
|
|
Success = false,
|
|
Message = $"موجودی محصول '{product.Title}' کافی نیست"
|
|
};
|
|
}
|
|
|
|
// Check if product is active
|
|
if (!product.IsActive)
|
|
{
|
|
return new PlaceOrderResponseDto
|
|
{
|
|
Success = false,
|
|
Message = $"محصول '{product.Title}' غیرفعال است"
|
|
};
|
|
}
|
|
|
|
// Calculate discount for this product
|
|
var itemTotal = product.Price * cartItem.Count;
|
|
var maxDiscountForItem = (itemTotal * product.MaxDiscountPercent) / 100;
|
|
|
|
totalAmount += itemTotal;
|
|
totalDiscountAmount += maxDiscountForItem;
|
|
|
|
orderDetails.Add(new DiscountOrderDetail
|
|
{
|
|
ProductId = product.Id,
|
|
Count = cartItem.Count,
|
|
UnitPrice = product.Price,
|
|
DiscountPercentUsed = product.MaxDiscountPercent,
|
|
DiscountAmount = maxDiscountForItem,
|
|
FinalPrice = itemTotal - maxDiscountForItem
|
|
});
|
|
}
|
|
|
|
// Validate discount balance usage
|
|
var maxDiscountBalanceUsable = totalDiscountAmount;
|
|
var actualDiscountBalanceUsed = Math.Min(request.DiscountBalanceToUse, maxDiscountBalanceUsable);
|
|
actualDiscountBalanceUsed = Math.Min(actualDiscountBalanceUsed, userWallet.DiscountBalance);
|
|
|
|
if (actualDiscountBalanceUsed < request.DiscountBalanceToUse)
|
|
{
|
|
return new PlaceOrderResponseDto
|
|
{
|
|
Success = false,
|
|
Message = $"موجودی تخفیف کافی نیست. حداکثر قابل استفاده: {maxDiscountBalanceUsable:N0} تومان، موجودی شما: {userWallet.DiscountBalance:N0} تومان"
|
|
};
|
|
}
|
|
|
|
var gatewayAmountRequired = totalAmount - actualDiscountBalanceUsed;
|
|
|
|
// Calculate VAT using centralized calculator
|
|
var vatBreakdown = VatCalculator.CalculateBreakdown(gatewayAmountRequired);
|
|
var vatAmount = vatBreakdown.VatAmount;
|
|
var finalGatewayAmount = vatBreakdown.GrossAmount;
|
|
|
|
// Create transaction for gateway payment
|
|
var transaction = new Transaction
|
|
{
|
|
Amount = finalGatewayAmount,
|
|
Description = $"خرید از فروشگاه تخفیف - مبلغ کل: {totalAmount:N0}، اعتبار تخفیف: {actualDiscountBalanceUsed:N0}",
|
|
PaymentStatus = PaymentStatus.Pending,
|
|
Type = TransactionType.DiscountShopPurchase
|
|
};
|
|
|
|
_context.Transactions.Add(transaction);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
|
|
// Create order
|
|
var order = new DiscountOrder
|
|
{
|
|
UserId = request.UserId,
|
|
TotalAmount = totalAmount,
|
|
DiscountBalanceUsed = actualDiscountBalanceUsed,
|
|
GatewayAmountPaid = finalGatewayAmount,
|
|
VatAmount = vatAmount,
|
|
PaymentStatus = PaymentStatus.Pending,
|
|
TransactionId = transaction.Id,
|
|
UserAddressId = request.UserAddressId,
|
|
DeliveryStatus = DeliveryStatus.Pending
|
|
};
|
|
|
|
_context.DiscountOrders.Add(order);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
|
|
// Add order details
|
|
foreach (var detail in orderDetails)
|
|
{
|
|
detail.DiscountOrderId = order.Id;
|
|
}
|
|
|
|
_context.DiscountOrderDetails.AddRange(orderDetails);
|
|
|
|
// رزرو موجودی برای سفارش pending
|
|
foreach (var cartItem in cartItems)
|
|
{
|
|
await _inventoryService.ReserveStockAsync(
|
|
cartItem.ProductId,
|
|
ProductType.DiscountProduct,
|
|
cartItem.Count,
|
|
order.Id,
|
|
cancellationToken);
|
|
}
|
|
|
|
// Clear cart
|
|
_context.DiscountShoppingCarts.RemoveRange(cartItems);
|
|
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
|
|
return new PlaceOrderResponseDto
|
|
{
|
|
Success = true,
|
|
Message = "سفارش ایجاد شد. لطفا پرداخت را تکمیل کنید",
|
|
OrderId = order.Id,
|
|
TransactionId = transaction.Id,
|
|
TotalAmount = totalAmount,
|
|
DiscountBalanceUsed = actualDiscountBalanceUsed,
|
|
GatewayAmountRequired = finalGatewayAmount
|
|
};
|
|
}
|
|
}
|