Compare commits
4 Commits
37a017998c
...
4e8caa6e2c
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e8caa6e2c | |||
| cdd124ac25 | |||
| 4d7932f335 | |||
| 18a2299d93 |
+24
@@ -10,15 +10,18 @@ public class CancelOrderByAdminCommandHandler : IRequestHandler<CancelOrderByAdm
|
|||||||
{
|
{
|
||||||
private readonly IApplicationDbContext _context;
|
private readonly IApplicationDbContext _context;
|
||||||
private readonly ICurrentUserService _currentUser;
|
private readonly ICurrentUserService _currentUser;
|
||||||
|
private readonly IInventoryService _inventoryService;
|
||||||
private readonly ILogger<CancelOrderByAdminCommandHandler> _logger;
|
private readonly ILogger<CancelOrderByAdminCommandHandler> _logger;
|
||||||
|
|
||||||
public CancelOrderByAdminCommandHandler(
|
public CancelOrderByAdminCommandHandler(
|
||||||
IApplicationDbContext context,
|
IApplicationDbContext context,
|
||||||
ICurrentUserService currentUser,
|
ICurrentUserService currentUser,
|
||||||
|
IInventoryService inventoryService,
|
||||||
ILogger<CancelOrderByAdminCommandHandler> logger)
|
ILogger<CancelOrderByAdminCommandHandler> logger)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_currentUser = currentUser;
|
_currentUser = currentUser;
|
||||||
|
_inventoryService = inventoryService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +36,7 @@ public class CancelOrderByAdminCommandHandler : IRequestHandler<CancelOrderByAdm
|
|||||||
var order = await _context.UserOrders
|
var order = await _context.UserOrders
|
||||||
.Include(x => x.User)
|
.Include(x => x.User)
|
||||||
.ThenInclude(x => x.UserWallets)
|
.ThenInclude(x => x.UserWallets)
|
||||||
|
.Include(x => x.FactorDetails)
|
||||||
.FirstOrDefaultAsync(x => x.Id == request.OrderId && !x.IsDeleted, cancellationToken);
|
.FirstOrDefaultAsync(x => x.Id == request.OrderId && !x.IsDeleted, cancellationToken);
|
||||||
|
|
||||||
if (order == null)
|
if (order == null)
|
||||||
@@ -87,6 +91,26 @@ public class CancelOrderByAdminCommandHandler : IRequestHandler<CancelOrderByAdm
|
|||||||
|
|
||||||
await _context.SaveChangesAsync(cancellationToken);
|
await _context.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
// Restore inventory for each item (only if order was not yet delivered)
|
||||||
|
if (order.FactorDetails != null && order.FactorDetails.Any())
|
||||||
|
{
|
||||||
|
foreach (var item in order.FactorDetails)
|
||||||
|
{
|
||||||
|
var restored = await _inventoryService.ProcessReturnAsync(
|
||||||
|
item.ProductId, ProductType.RegularProduct,
|
||||||
|
item.Count, order.Id,
|
||||||
|
note: $"برگشت موجودی — لغو سفارش #{order.Id} توسط Admin",
|
||||||
|
ct: cancellationToken);
|
||||||
|
|
||||||
|
if (!restored)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"Failed to restore inventory for ProductId={ProductId} on cancel OrderId={OrderId}",
|
||||||
|
item.ProductId, order.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_logger.LogInformation(
|
_logger.LogInformation(
|
||||||
"Order cancelled by admin. OrderId: {OrderId}, Reason: {Reason}, Refunded: {Refunded}, Admin: {AdminId}",
|
"Order cancelled by admin. OrderId: {OrderId}, Reason: {Reason}, Refunded: {Refunded}, Admin: {AdminId}",
|
||||||
order.Id,
|
order.Id,
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public static class SystemConstants
|
|||||||
/// مقدار ۱٬۰۰۰٬۰۰۰ ریال = ۱۰۰ هزار تومان
|
/// مقدار ۱٬۰۰۰٬۰۰۰ ریال = ۱۰۰ هزار تومان
|
||||||
/// (Q24: چون قیمت محصولات متفاوت است، موجودی دقیقاً صفر نمیشود)
|
/// (Q24: چون قیمت محصولات متفاوت است، موجودی دقیقاً صفر نمیشود)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const long MagicWalletEntryThreshold = 1_000_000;
|
public const long MagicWalletEntryThreshold = 100_000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// مقدار پیشفرض ضریب جادویی وقتی پکیج یافت نشود (بازگشت به پایه)
|
/// مقدار پیشفرض ضریب جادویی وقتی پکیج یافت نشود (بازگشت به پایه)
|
||||||
@@ -74,12 +74,12 @@ public static class SystemConstants
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// مقدار پیشفرض حداکثر واریز جادویی وقتی پکیج یافت نشود (ریال)
|
/// مقدار پیشفرض حداکثر واریز جادویی وقتی پکیج یافت نشود (ریال)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const long MagicWalletDefaultMaxDeposit = 1_000_000_000;
|
public const long MagicWalletDefaultMaxDeposit = 100_000_000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// مقدار پیشفرض حداکثر اعتبار جادویی وقتی پکیج یافت نشود (ریال)
|
/// مقدار پیشفرض حداکثر اعتبار جادویی وقتی پکیج یافت نشود (ریال)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const long MagicWalletDefaultMaxCredit = 2_500_000_000;
|
public const long MagicWalletDefaultMaxCredit = 250_000_000;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|||||||
@@ -29,12 +29,14 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
|
|||||||
private readonly ISender _sender;
|
private readonly ISender _sender;
|
||||||
private readonly IApplicationDbContext _context;
|
private readonly IApplicationDbContext _context;
|
||||||
private readonly ICurrentUserService _currentUserService;
|
private readonly ICurrentUserService _currentUserService;
|
||||||
|
private readonly IInventoryService _inventoryService;
|
||||||
|
|
||||||
public UserOrderService(ISender sender, IApplicationDbContext context, ICurrentUserService currentUserService)
|
public UserOrderService(ISender sender, IApplicationDbContext context, ICurrentUserService currentUserService, IInventoryService inventoryService)
|
||||||
{
|
{
|
||||||
_sender = sender;
|
_sender = sender;
|
||||||
_context = context;
|
_context = context;
|
||||||
_currentUserService = currentUserService;
|
_currentUserService = currentUserService;
|
||||||
|
_inventoryService = inventoryService;
|
||||||
}
|
}
|
||||||
[RequiresPermission(PermissionNames.OrdersCreate)]
|
[RequiresPermission(PermissionNames.OrdersCreate)]
|
||||||
public override async Task<CreateNewUserOrderResponse> CreateNewUserOrder(CreateNewUserOrderRequest request, ServerCallContext context)
|
public override async Task<CreateNewUserOrderResponse> CreateNewUserOrder(CreateNewUserOrderRequest request, ServerCallContext context)
|
||||||
@@ -286,6 +288,18 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
|
|||||||
$"مبلغ نامعتبر است. محاسبه شده: {totalAmount}, دریافتی: {request.TotalAmount}"));
|
$"مبلغ نامعتبر است. محاسبه شده: {totalAmount}, دریافتی: {request.TotalAmount}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate stock availability for all cart items before any financial operation
|
||||||
|
foreach (var cartItem in cartItems)
|
||||||
|
{
|
||||||
|
var available = await _inventoryService.GetAvailableQuantityAsync(
|
||||||
|
cartItem.ProductId, ProductType.RegularProduct, ct: context.CancellationToken);
|
||||||
|
if (available < cartItem.Count)
|
||||||
|
{
|
||||||
|
throw new RpcException(new Status(StatusCode.FailedPrecondition,
|
||||||
|
$"موجودی «{cartItem.Product.Title}» کافی نیست. موجود: {available}، درخواستی: {cartItem.Count}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get user's wallet
|
// Get user's wallet
|
||||||
var wallet = await _context.UserWallets
|
var wallet = await _context.UserWallets
|
||||||
.Where(w => w.UserId == userId)
|
.Where(w => w.UserId == userId)
|
||||||
@@ -338,7 +352,7 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
|
|||||||
_context.UserWalletHistories.Add(walletLog);
|
_context.UserWalletHistories.Add(walletLog);
|
||||||
|
|
||||||
// ═══ Magic Wallet: Entry / Exit Trigger ═══
|
// ═══ Magic Wallet: Entry / Exit Trigger ═══
|
||||||
// Q24: آستانه <= 1,000,000 ریال به جای == 0 (چون قیمت محصولات متفاوت است)
|
// Q24: آستانه <= 1,00,000 تومان به جای == 0 (چون قیمت محصولات متفاوت است)
|
||||||
if (wallet.Balance <= SystemConstants.MagicWalletEntryThreshold)
|
if (wallet.Balance <= SystemConstants.MagicWalletEntryThreshold)
|
||||||
{
|
{
|
||||||
var user = await _context.Users
|
var user = await _context.Users
|
||||||
@@ -463,6 +477,18 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
|
|||||||
|
|
||||||
await _context.SaveChangesAsync(context.CancellationToken);
|
await _context.SaveChangesAsync(context.CancellationToken);
|
||||||
|
|
||||||
|
// Deduct inventory and update SaleCount for each purchased item
|
||||||
|
foreach (var cartItem in cartItems)
|
||||||
|
{
|
||||||
|
await _inventoryService.ConfirmSaleAsync(
|
||||||
|
cartItem.ProductId, ProductType.RegularProduct,
|
||||||
|
cartItem.Count, order.Id, context.CancellationToken);
|
||||||
|
|
||||||
|
cartItem.Product.SaleCount += cartItem.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync(context.CancellationToken);
|
||||||
|
|
||||||
return new SubmitShopBuyOrderResponse
|
return new SubmitShopBuyOrderResponse
|
||||||
{
|
{
|
||||||
Id = order.Id
|
Id = order.Id
|
||||||
|
|||||||
Reference in New Issue
Block a user