using Dlhis.Canteen.Dishes.Request; using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; using Kurisu.AspNetCore.Utils.Extensions; using Kurisu.AspNetCore.Utils; using Kurisu.Core.DataAccess.Dto; using Kurisu.SqlSugar.Services; using Kurisu.Core.User.Abstractions; using Dlhis.Canteen.Setting.Services; using Dlhis.Basic.Api; using Kurisu.SqlSugar.Extensions; using SqlSugar; using Mapster; namespace Dlhis.Canteen.Order.Services.Implements; public class BookingOrderService : BaseOrderService, IBookingOrderService { private readonly IDbContext _dbContext; private readonly ICurrentUser _currentUser; private readonly IDisheMenuApi _disheMenuApi; public BookingOrderService(ICanteenSettingService canteenSettingService, IDisheMenuApi disheMenuApi) : base(canteenSettingService) { _disheMenuApi = disheMenuApi; } public async Task BookingAsync(BookingMealRequest request) { var gainfo = await CheckExistsMyBookingsAsync(request.BookingDate, request.ShiftType); var businessPlace = await _dbContext.Queryable().Where(x => x.Code == request.BusinessPlaceCode).FirstAsync(); //预定时间 var now = DateTime.Now; var bookingDeadline = await GetSettingAsync(CanteenSettingItemEnumType.BookingDeadline) ?? new TimeOnly(20, 30, 00); var dealLine = DateTime.Today.Add(bookingDeadline.ToTimeSpan()); (now >= dealLine).ThrowIfTrue("超出订餐时间"); //菜单存在 var menuDetailResult = await _disheMenuApi.GetBookingDishesDetailAsync(request.BookingDate, request.BusinessPlaceCode, (int)request.ShiftType, request.DishesCode); var menuDetail = menuDetailResult.Data; menuDetail.ThrowIfNull("预定失败,菜品已经下架"); var order = new CanteenOrderEntity { RequestJson = request.ToJson(), ThirdNo = string.Empty, Type = BalanceRecordTypeEnumType.Out, ApplicationType = CanteenApplicaitonTypeEnumType.Booking, Name = gainfo.Name, Source = request.Source, UserNo = gainfo.No, UserCode = gainfo.Code, Amount = -Math.Abs(menuDetail.Price * request.Number), BusinessPlaceCode = request.BusinessPlaceCode, BusinessShiftCode = null, ShiftType = request.ShiftType, CostDate = now.Date, CostId = gainfo.CostId, DepartmentNo = gainfo.DepartmentNo, DeviceUniqueNo = string.Empty, DeliveryAddress = request.DeliveryAddress, No = SnowFlakeHelper.Instance.NextId().ToString(), SubsidiesFromMonth = now.ToString("yyyyMM"), IsOffline = false, IsCostCrossTenant = await GetSettingAsync(CanteenSettingItemEnumType.AllowCrossTenant), OriginTenantId = gainfo.Factory,//人员可能跨基地消费 Status = BalanceRecordStatusEnumType.Valid, OrderStatus = CanteenOrderStatusEnumType.Success, CostDateTime = now, //标识当前消费的基地 TenantId = businessPlace.TenantId, }; var orderId = await _dbContext.InsertReturnIdentityAsync(order); await ContinueUpdateAsync(async () => { await _disheMenuApi.GetBookingDishesDetailAsync(request.BookingDate, request.BusinessPlaceCode, (int)request.ShiftType, request.DishesCode); var menuDetail = menuDetailResult.Data; menuDetail.ThrowIfNull("预定失败,菜品已经下架"); menuDetail.Number -= request.Number; (menuDetail.Number < 0).ThrowIfTrue($"{menuDetail.DishesName}已售罄"); //餐补 if (request.Source == BalanceRecordSourceEnumType.LocalTenantSubsidies) { var mealInfo = await _dbContext.Queryable().Where(x => x.UserNo == order.UserNo).FirstAsync(); if (mealInfo == null) { await _dbContext.InsertAsync(new GainfoMealEntity { Balance = 0, BalanceOfRecharge = 0, BalanceOfSubsidies = 0, UserCode = gainfo.Code, UserNo = gainfo.No, Version = 0, }); (mealInfo == null).ThrowIfTrue("余额不足,无法消费"); } //金额+- mealInfo.Balance += order.Amount; (mealInfo.Balance < 0).ThrowIfTrue("余额不足,无法消费"); var effectMeal = await _dbContext.Updateable() .SetColumns(x => x.Balance == mealInfo.Balance) .SetColumns(x => x.Version == x.Version + 1) .Where(x => x.UserNo == order.UserNo && x.Version == mealInfo.Version)//必须与查询时的version一致 .ExecuteCommandAsync(); if (effectMeal <= 0) throw new VersionExceptions("更新版本冲突"); } var effectMenu = await _dbContext.Updateable() .SetColumns(x => x.Number == menuDetail.Number) .SetColumns(x => x.Version == x.Version + 1) .SetColumns(x => x.ModifiedTime == now) .Where(x => x.Date == menuDetail.Date && x.ShiftType == request.ShiftType && x.BusinessPlaceCode == request.BusinessPlaceCode && x.DishesCode == request.DishesCode && x.Version == menuDetail.Version ) .ExecuteCommandAsync(); if (effectMenu <= 0) throw new VersionExceptions("更新版本冲突"); //写入记录 var balanceRecord = order.Adapt(); await _dbContext.InsertAsync(balanceRecord); await _dbContext.InsertAsync(new CanteenOrderDetailEntity { OrderNo = order.No, DishesCode = request.DishesCode, Price = menuDetail.Price, //Unit Number = 1, }); }, 10); return new BookingResponse { No = order.No, CreateTime = order.CreateTime, Source = order.Source, Amount = Math.Abs(order.Amount) }; } public async Task> GetBookingPageAsync(OrderBookingPageRequest request) { var page = await _dbContext.Queryable() .LeftJoin((x, ga) => x.UserNo == ga.No) .Select(x => new OrderBookingResponse { No = x.No, DeliveryAddress = x.DeliveryAddress, Remark = x.Remark, Amount = x.Amount }) .ToPageListAsync(request); return page; } public async Task CancelOrderAsync() { throw new NotImplementedException(); } /// /// 检查我的订餐是否存在,存在抛出异常 /// /// /// /// private async Task CheckExistsMyBookingsAsync(DateTime bookingDate, ShiftEnumType shiftType) { var subjectId = _currentUser.GetIntSubjectId(); var gainfo = await _dbContext.Queryable().Where(x => x.IdentityUserId == subjectId).FirstAsync(); var jinkoCode = _currentUser.GetUserClaim("jinko-code") ?? string.Empty; if (jinkoCode.IsPresent()) { gainfo = await _dbContext.Queryable().Where(x => x.Code == jinkoCode).FirstAsync(); } var start = bookingDate.Date.AddDays(-1); var end = start.AddDays(1).AddSeconds(-1); var exists = await _dbContext.Queryable() .Where(x => x.ApplicationType == CanteenApplicaitonTypeEnumType.Booking) .Where(x => x.ShiftType == shiftType) .Where(x => x.UserNo == gainfo.No) .Where(x => x.CreateTime >= start && x.CreateTime <= end) .AnyAsync(); exists.ThrowIfTrue("不可重复订餐"); return gainfo; } }