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; } } }