58 lines
2.1 KiB
C#
58 lines
2.1 KiB
C#
using MediatR;
|
|
using Microsoft.Extensions.Logging;
|
|
using TakeoutSaaS.Application.App.Inventory.Commands;
|
|
using TakeoutSaaS.Domain.Inventory.Enums;
|
|
using TakeoutSaaS.Domain.Inventory.Repositories;
|
|
|
|
namespace TakeoutSaaS.Application.App.Inventory.Handlers;
|
|
|
|
/// <summary>
|
|
/// 释放过期锁定处理器。
|
|
/// </summary>
|
|
public sealed class ReleaseExpiredInventoryLocksCommandHandler(
|
|
IInventoryRepository inventoryRepository,
|
|
ILogger<ReleaseExpiredInventoryLocksCommandHandler> logger)
|
|
: IRequestHandler<ReleaseExpiredInventoryLocksCommand, int>
|
|
{
|
|
/// <inheritdoc />
|
|
public async Task<int> Handle(ReleaseExpiredInventoryLocksCommand request, CancellationToken cancellationToken)
|
|
{
|
|
// 1. 查询过期锁
|
|
var now = DateTime.UtcNow;
|
|
var expiredLocks = await inventoryRepository.FindExpiredLocksAsync(null, now, cancellationToken);
|
|
if (expiredLocks.Count == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// 2. 释放锁对应库存
|
|
var affected = 0;
|
|
foreach (var lockRecord in expiredLocks)
|
|
{
|
|
var item = await inventoryRepository.GetForUpdateAsync(lockRecord.TenantId, lockRecord.StoreId, lockRecord.ProductSkuId, cancellationToken);
|
|
if (item is null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (lockRecord.IsPresale)
|
|
{
|
|
item.PresaleLocked = Math.Max(0, item.PresaleLocked - lockRecord.Quantity);
|
|
}
|
|
else
|
|
{
|
|
item.QuantityReserved = Math.Max(0, item.QuantityReserved - lockRecord.Quantity);
|
|
}
|
|
|
|
item.IsSoldOut = item.QuantityOnHand - item.QuantityReserved - item.PresaleLocked <= (item.SafetyStock ?? 0);
|
|
await inventoryRepository.UpdateItemAsync(item, cancellationToken);
|
|
await inventoryRepository.MarkLockStatusAsync(lockRecord, InventoryLockStatus.Released, cancellationToken);
|
|
affected++;
|
|
}
|
|
|
|
await inventoryRepository.SaveChangesAsync(cancellationToken);
|
|
logger.LogInformation("释放过期库存锁定 {Count} 条", affected);
|
|
return affected;
|
|
}
|
|
}
|