feat: implement user wallet charging and transaction logging for Daya loan processing
This commit is contained in:
+53
-24
@@ -10,6 +10,7 @@ public class
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ILogger<SubmitShopBuyOrderCommandHandler> _logger;
|
||||
private float _vatRate;
|
||||
|
||||
public SubmitShopBuyOrderCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
@@ -35,7 +36,7 @@ public class
|
||||
// چک موجودی محصولات
|
||||
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)
|
||||
@@ -44,33 +45,55 @@ public class
|
||||
}
|
||||
else if (cartItem.Product.RemainingCount < cartItem.Count)
|
||||
{
|
||||
insufficientStockProducts.Add((cartItem.Product.Title, cartItem.Count, cartItem.Product.RemainingCount));
|
||||
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 =>
|
||||
var messages = insufficientStockProducts.Select(p =>
|
||||
$"«{p.Title}»: درخواست {p.Requested} عدد، موجودی {p.Available} عدد");
|
||||
throw new Exception($"موجودی محصولات زیر کافی نیست: {string.Join(" | ", messages)}");
|
||||
}
|
||||
|
||||
if (user.UserCarts.Sum(s => s.Count * s.Product.Price) != request.TotalAmount)
|
||||
long finalAmount = 0;
|
||||
var vatIsEnable =
|
||||
_context.SystemConfigurations
|
||||
.FirstOrDefault(f => f.Scope == ConfigurationScope.VAT && f.Key == "IsEnabled")?.Value ??
|
||||
"0";
|
||||
if (vatIsEnable=="1")
|
||||
{
|
||||
_vatRate = float.Parse(
|
||||
_context.SystemConfigurations
|
||||
.FirstOrDefault(f => f.Scope == ConfigurationScope.VAT && f.Key == "Shop.VAT")?.Value ??
|
||||
throw new InvalidOperationException());
|
||||
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)
|
||||
|
||||
if (userWallet.Balance <= 0 || userWallet.Balance < request.TotalAmount)
|
||||
throw new Exception("موجودی کیف پول کاربر برای انجام این تراکنش کافی نیست.");
|
||||
|
||||
|
||||
var newTransaction = new Transaction()
|
||||
{
|
||||
Amount = request.TotalAmount,
|
||||
@@ -82,18 +105,18 @@ public class
|
||||
};
|
||||
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,
|
||||
ChangeValue = -1 * request.TotalAmount,
|
||||
IsIncrease = false,
|
||||
RefrenceId = newTransaction.Id,
|
||||
};
|
||||
userWallet.Balance -= request.TotalAmount;
|
||||
|
||||
|
||||
await _context.UserWalletChangeLogs.AddAsync(newWalletLog, cancellationToken);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
@@ -111,7 +134,7 @@ public class
|
||||
};
|
||||
await _context.UserOrders.AddAsync(newOrder, cancellationToken);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
|
||||
// محاسبه و ثبت VAT (اگر فعال باشد)
|
||||
var vatCreated = await CalculateAndSaveVAT(newOrder.Id, request.TotalAmount, cancellationToken);
|
||||
if (vatCreated)
|
||||
@@ -119,37 +142,43 @@ public class
|
||||
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,
|
||||
UnitPrice =vatIsEnable=="1" ?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.",
|
||||
|
||||
_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
|
||||
@@ -166,7 +195,7 @@ public class
|
||||
|
||||
// دریافت نرخ VAT
|
||||
var vatRateConfig = await _context.SystemConfigurations
|
||||
.FirstOrDefaultAsync(x => x.Scope == ConfigurationScope.VAT && x.Key == "Rate", cancellationToken);
|
||||
.FirstOrDefaultAsync(x => x.Scope == ConfigurationScope.VAT && x.Key == "Shop.VAT", cancellationToken);
|
||||
|
||||
if (vatRateConfig == null || !decimal.TryParse(vatRateConfig.Value, out var vatRate))
|
||||
{
|
||||
@@ -201,7 +230,7 @@ public class
|
||||
vatAmount,
|
||||
totalAmount
|
||||
);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -211,4 +240,4 @@ public class
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user