using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.Utils; using Kurisu.AspNetCore.Utils.Extensions; namespace Dlhis.Canteen.Order.Repository.Implements; public class BalanceRepository : IBalanceRepository { private readonly IDbContext _dbContext; public BalanceRepository(IDbContext dbContext) { _dbContext = dbContext; } public async Task GetBalanceAsync(string userCode) { // var queryable = _dbContext.Queryable() // .Where(x => x.UserCode == userCode && x.Status == BalanceRecordStatusEnumType.Valid) // .Where(x => x.Source != BalanceRecordSourceEnumType.EMealVoucher); // // if (!factory.IsPresent()) // { // return await queryable.SumAsync(x => x.Amount); // } // // var factories = await GetWalletFactoriesAsync(factory); // return await queryable.Where(x => factories.Contains(x.TenantId)).SumAsync(x => x.Amount); return await _dbContext.Queryable().Where(x => x.UserCode == userCode).Select(x => x.Balance).SingleAsync(); } public async Task> GetBalanceRecordsAsync(string userCode, string factory, DateTime startTime, DateTime endTime) { var factories = await GetWalletFactoriesAsync(factory); return await _dbContext.Queryable() .Where(x => x.UserCode == userCode) .Where(x => factories.Contains(x.TenantId)) .Where(x => x.Type == BalanceRecordTypeEnumType.Out) .Where(x => x.Status == BalanceRecordStatusEnumType.Valid) .Where(x => x.CostDateTime >= startTime && x.CostDateTime <= endTime) .ToListAsync(); } public async Task> GetWalletFactoriesAsync(string factory) { var wallets = await _dbContext.Queryable().ToListAsync(); var code = wallets.First(x => x.Factory == factory).Code; return wallets.Where(x => x.Code == code).Select(x => x.Factory).ToList(); } /// public async Task ConsumeBalanceAsync(string userCode, decimal cost) { await CommonHelper.RetryAsync(async () => { if (!await _dbContext.Queryable().Where(x => x.UserCode == userCode).AnyAsync()) { await CalculateBalanceAsync(userCode); } var data = await _dbContext.Queryable() .Where(x => x.UserCode == userCode) .Select(x => new { x.Balance, x.Version }) .SingleAsync(); var currentBalance = data.Balance - Math.Abs(cost); var isEnough = currentBalance >= 0; isEnough.ThrowIfFalse($"钱包余额不足({data.Balance}元)"); await _dbContext.Updateable() .SetColumns(x => x.Balance == currentBalance) .SetColumns(x => x.Version == data.Version + 1) .SetColumns(x => x.ModifiedTime == DateTime.Now) .Where(x => x.UserCode == userCode && x.Version == data.Version) .ExecuteCommandThrowVersionAsync(); }); } public async Task CalculateBalanceAsync(string userCode) { if (!await _dbContext.Queryable().Where(x => x.UserCode == userCode).AnyAsync()) { await _dbContext.InsertAsync(new UserBalanceEntity { UserCode = userCode, Balance = 0, Version = 0 }); } await CommonHelper.RetryAsync(async () => { var balance = await _dbContext.Queryable() .Where(x => x.UserCode == userCode) .Where(x => x.Status == BalanceRecordStatusEnumType.Valid) .Where(x => !BalanceRecordSourceConstants.IgnoreSources.Contains(x.Source)) .SumAsync(x => x.Amount); var version = await _dbContext.Queryable() .Where(x => x.UserCode == userCode) .Select(x => x.Version) .SingleAsync(); await _dbContext.Updateable() .SetColumns(x => x.Balance == balance) .SetColumns(x => x.Version == version + 1) .SetColumns(x => x.ModifiedTime == DateTime.Now) .Where(x => x.UserCode == userCode && x.Version == version) .ExecuteCommandThrowVersionAsync(); }, 5); } }