using MAX.Framework.Commons;
using MAX.Framework.Mediation;
using MediatR;
using Store.Users.Entities;
namespace Store.Users.Behaviors;
/// 锁定积分账户并检查消费额度,不依赖商铺信息。
public sealed class AccountConsumptionBehavior(
UnitOfWorkExecutionContext executionContext)
: IPipelineBehavior
where TRequest : class, IRequest, IAccountConsumptionRequest
{
public async Task Handle(TRequest request, CancellationToken cancellationToken,
RequestHandlerDelegate next)
{
cancellationToken.ThrowIfCancellationRequested();
if (string.IsNullOrWhiteSpace(request.UserName))
throw new AppException("用户名不能为空");
var userName = request.UserName.Trim();
var user = await executionContext.Orm.Select().Where(a => a.UserName == userName)
.ForUpdate().FirstAsync(cancellationToken)
?? throw new AppException("不存在的用户");
var quote = request.CalculateConsumption(user);
if (quote.Amount <= 0 || quote.UnitPrice <= 0)
throw new AppException("消费金额必须大于0");
if (user.Points < quote.Amount)
throw new AppException("余额不足");
lock (request)
{
if (request.ConsumptionContext != null)
throw new InvalidOperationException("同一个消费命令不能同时执行");
request.ConsumptionContext = new AccountConsumptionContext(user, quote);
}
try
{
return await next();
}
finally
{
request.ConsumptionContext = null;
}
}
}