fix(regular-store): deduct inventory and restore on cancel
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 19m38s

- UserOrderService.SubmitShopBuyOrder: inject IInventoryService; validate
  available stock per item before any financial operation; call ConfirmSaleAsync
  and increment Product.SaleCount after order is persisted.
- CancelOrderByAdminCommandHandler: inject IInventoryService; include
  FactorDetails in query; call ProcessReturnAsync for each item so stock
  is restored when an order is cancelled by admin.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
masoodafar-web
2026-05-17 21:57:48 +03:30
parent 18a2299d93
commit 4d7932f335
2 changed files with 51 additions and 1 deletions
@@ -29,12 +29,14 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
private readonly ISender _sender;
private readonly IApplicationDbContext _context;
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;
_context = context;
_currentUserService = currentUserService;
_inventoryService = inventoryService;
}
[RequiresPermission(PermissionNames.OrdersCreate)]
public override async Task<CreateNewUserOrderResponse> CreateNewUserOrder(CreateNewUserOrderRequest request, ServerCallContext context)
@@ -285,6 +287,18 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
throw new RpcException(new Status(StatusCode.InvalidArgument,
$"مبلغ نامعتبر است. محاسبه شده: {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
var wallet = await _context.UserWallets
@@ -461,6 +475,18 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
cartItem.IsDeleted = true;
}
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