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 Dlhis.Entity.Device.Entities; using Dlhis.Entity.Device.Enums; using Dlhis.Sys.Api; using Kurisu.AspNetCore.UnifyResultAndValidation; using Kurisu.AspNetCore.Utils.Extensions; using Kurisu.Core.DataAccess.Dto; using Kurisu.Core.User.Abstractions; using Kurisu.SqlSugar.Extensions; using Kurisu.SqlSugar.Services; using Mapster; using SqlSugar; namespace Dlhis.Canteen.Order.Services.Implements; public class BalanceService : IBalanceService { private readonly IDbContext _dbContext; private readonly ICurrentUser _currentUser; private readonly ILogger _logger; private readonly ITenantApi _tenantApi; public BalanceService(IDbContext dbContext, ICurrentUser currentUser, ILogger logger, ITenantApi tenantApi) { _dbContext = dbContext; _currentUser = currentUser; _logger = logger; _tenantApi = tenantApi; } public async Task> GetPageAsync(BalanceRecordPageRequest request) { var page = await _dbContext.Queryable() .LeftJoin((record, ga) => record.UserNo == ga.No) .LeftJoin((record, ga, department) => ga.DepartmentNo == department.No) .LeftJoin((record, ga, department, bplace) => record.BusinessPlaceCode == bplace.Code) .LeftJoin((record, ga, department, bplace, bshift) => record.BusinessShiftCode == bshift.Code) .WhereIF(request.SearchDateTimePeriod?.Start.HasValue == true, record => record.CostDate >= request.SearchDateTimePeriod.Start) .WhereIF(request.SearchDateTimePeriod?.End.HasValue == true, record => record.CostDate <= request.SearchDateTimePeriod.End) .WhereIF(request.BusinessplaceCodes.IsPresent(), record => request.BusinessplaceCodes.Contains(record.BusinessPlaceCode)) .WhereIF(request.ShiftTypes.IsPresent(), record => request.ShiftTypes.Contains(record.ShiftType)) .WhereIF(request.Type.HasValue, record => record.Type == request.Type) .WhereIF(request.Search.IsPresent(), (record, ga) => ga.Name.Contains(request.Search) || ga.Code.Contains(request.Search) ) .OrderBy(record => record.CreateTime, OrderByType.Desc) .Select((record, ga, department, bplace, bshift) => new BalanceRecordResponse { Id = record.Id, Amount = record.Amount, BusinessPlaceCode = record.BusinessPlaceCode, BusinessShiftCode = record.BusinessShiftCode, CostDate = record.CostDate, CostId = record.CostId, DepartmentNo = record.DepartmentNo, DeviceInfo = record.DeviceUniqueNo, IP = record.IP, UserNo = record.UserNo, UserCode = record.UserCode, Type = record.Type, SubsidiesFromMonth = record.SubsidiesFromMonth, Status = record.Status, Source = record.Source, No = record.No, IsCostCrossTenant = record.IsCostCrossTenant, OriginTenantId = record.OriginTenantId, Name = record.Name, DepartmentName = department.Name, BusinessPlaceName = bplace.Name, BusinessShiftName = bshift.Name, CostDateTime = record.CostDateTime, TenantId = record.TenantId, }) .ToPageListAsync(request); page.Data.ForEach(item => { item.Amount = Math.Abs(item.Amount); }); try { var tenantResult = await _tenantApi.GetTenantsInternalAsync(); var tenants = tenantResult.Data; page.Data.ForEach(item => { item.TenantName = tenants.FirstOrDefault(x => x.Code == item.TenantId)?.Name; }); } catch (Exception) { } return page; } /// /// 根据成本中心 /// /// /// public async Task> RecordByCostIdAsync(BalanceRecordPageByCostIdRequest request) { var paeginfos = await _dbContext.Queryable() .WhereIF(!request.UserCode.IsEmpty(), record => record.UserCode == request.UserCode) .WhereIF(!request.DepartmentNo.IsEmpty(), record => record.DepartmentNo == request.DepartmentNo) .WhereIF(!request.OriginTenantId.IsEmpty(), record => record.OriginTenantId == request.OriginTenantId) .WhereIF(!request.CostId.IsEmpty(), record => record.CostId == request.CostId) .WhereIF(request.StartDatetime.HasValue, record => record.CostDateTime >= request.StartDatetime) .WhereIF(request.EndDatetime.HasValue, record => record.CostDateTime <= request.EndDatetime) .Where(record => record.Type == BalanceRecordTypeEnumType.Out) .OrderBy(record => record.CreateTime, OrderByType.Desc) .ToListAsync(); var lst = new List(); foreach (var costIdGroup in paeginfos.GroupBy(record => record.CostId)) { //每个costID var obj = new BalanceRecordCostIdResponse { CostId = costIdGroup.Key }; // 所有人次 var BreakfastNumberOfPeople = costIdGroup.Count(x => x.ShiftType == ShiftEnumType.Breakfast); var LunchNumberOfPeople = costIdGroup.Count(x => x.ShiftType == ShiftEnumType.Lunch); var DinnerNumberOfPeople = costIdGroup.Count(x => x.ShiftType == ShiftEnumType.Dinner); var LateNightNumberOfPeople = costIdGroup.Count(x => x.ShiftType == ShiftEnumType.Nightsnack); // 每个餐次人数 obj.BreakfastNumberOfPeople = costIdGroup.Where(x => x.ShiftType == ShiftEnumType.Breakfast).Select(x => x.UserNo).Distinct().Count(); obj.LunchNumberOfPeople = costIdGroup.Where(x => x.ShiftType == ShiftEnumType.Lunch).Select(x => x.UserNo).Distinct().Count(); obj.DinnerNumberOfPeople = costIdGroup.Where(x => x.ShiftType == ShiftEnumType.Dinner).Select(x => x.UserNo).Distinct().Count(); obj.LateNightNumberOfPeople = costIdGroup.Where(x => x.ShiftType == ShiftEnumType.Nightsnack).Select(x => x.UserNo).Distinct().Count(); //餐次金额 obj.BreakfastAmount = Math.Abs(costIdGroup.Where(x => x.ShiftType == ShiftEnumType.Breakfast).Sum(x => x.Amount)); obj.LunchAmount = Math.Abs(costIdGroup.Where(x => x.ShiftType == ShiftEnumType.Lunch).Sum(x => x.Amount)); obj.DinnerAmount = Math.Abs(costIdGroup.Where(x => x.ShiftType == ShiftEnumType.Dinner).Sum(x => x.Amount)); obj.LateNightAmount = Math.Abs(costIdGroup.Where(x => x.ShiftType == ShiftEnumType.Nightsnack).Sum(x => x.Amount)); // 每个餐次单价 obj.BreakfastPrice = BreakfastNumberOfPeople == 0 ? 0 : Math.Round(obj.BreakfastAmount / BreakfastNumberOfPeople, 2); obj.LunchPrice = LunchNumberOfPeople == 0 ? 0 : Math.Round(obj.LunchAmount / LunchNumberOfPeople, 2); obj.DinnerPrice = DinnerNumberOfPeople == 0 ? 0 : Math.Round(obj.DinnerAmount / DinnerNumberOfPeople, 2); obj.LateNightPrice = LateNightNumberOfPeople == 0 ? 0 : Math.Round(obj.LateNightAmount / LateNightNumberOfPeople, 2); // 总人数 总金额 obj.TotalNumberOfPeople = costIdGroup.Select(x => x.UserNo).Distinct().Count(); obj.TotalAmount = obj.BreakfastAmount + obj.LunchAmount + obj.DinnerAmount + obj.LateNightAmount; lst.Add(obj); } // 分页操作 var startIndex = (request.PageIndex - 1) * request.PageSize; var pagedData = lst.Skip(startIndex).Take(request.PageSize).ToList(); var pagination = new Pagination { PageIndex = request.PageIndex, PageSize = request.PageSize, Total = lst.Count, // 使用原始列表的总数进行分页 Data = pagedData }; return pagination; } /// /// 消费明细 /// /// /// public async Task> RecordPageDetailsAsync(BalanceRecordPageDetailsRequest request) { var paeginfo = await _dbContext.Queryable() .LeftJoin((record, department) => record.DepartmentNo == department.No) .LeftJoin((record, department, bplace) => record.BusinessPlaceCode == bplace.Code) .LeftJoin((record, department, bplace, bshift) => record.BusinessShiftCode == bshift.Code) .LeftJoin((record, department, bplace, bshift, type) => record.BusinessShiftCode.ToString() == type.Code) .WhereIF(!request.Name.IsEmpty(), record => record.Name == request.Name) .WhereIF(!request.DepartmentNo.IsEmpty(), record => record.DepartmentNo == request.DepartmentNo) .WhereIF(!request.UserCode.IsEmpty(), record => record.UserCode == request.UserCode) .WhereIF(request.Type.HasValue, record => record.Type == request.Type) .WhereIF(request.BusinessShiftCode.HasValue, record => record.BusinessShiftCode == request.BusinessShiftCode) .WhereIF(request.BusinessPlaceCode.HasValue, record => record.BusinessPlaceCode == request.BusinessPlaceCode) .WhereIF(request.StartDatetime.HasValue, record => record.CostDateTime >= request.StartDatetime) .WhereIF(request.EndDatetime.HasValue, record => record.CostDateTime <= request.EndDatetime) .OrderBy(record => record.CreateTime, OrderByType.Desc) .Select((record, department, bplace, bshift, type) => new BalanceRecordResponse { Id = record.Id, Amount = record.Amount, BusinessPlaceCode = record.BusinessPlaceCode, BusinessShiftCode = record.BusinessShiftCode, CostDate = record.CostDate, CostId = record.CostId, DepartmentNo = record.DepartmentNo, DeviceInfo = record.DeviceUniqueNo, IP = record.IP, UserNo = record.UserNo, UserCode = record.UserCode, Type = record.Type, SubsidiesFromMonth = record.SubsidiesFromMonth, Status = record.Status, Source = record.Source, No = record.No, IsCostCrossTenant = record.IsCostCrossTenant, OriginTenantId = record.OriginTenantId, Name = record.Name, DepartmentName = department.Name, BusinessPlaceName = bplace.Name, BusinessShiftName = type.Display, CostDateTime = record.CreateTime // todo }) .ToPageListAsync(request); foreach (var item in paeginfo.Data) { item.Amount = Math.Abs(item.Amount); } return paeginfo; } /// /// 消费汇总 根据部门号 /// /// /// public async Task> BalanceRecordSummaryByNoAsync(BalanceRecordSummaryRequest request) { var paeginfos = await _dbContext.Queryable() .WhereIF(!request.DepartmentNo.IsEmpty(), record => record.DepartmentNo == request.DepartmentNo) .WhereIF(!request.UserCode.IsEmpty(), record => record.UserCode == request.UserCode) .WhereIF(!request.OriginTenantId.IsEmpty(), record => record.TenantId == request.OriginTenantId) .WhereIF(request.StartDatetime.HasValue, record => record.CostDateTime >= request.StartDatetime) .WhereIF(request.EndDatetime.HasValue, record => record.CostDateTime <= request.EndDatetime) .WhereIF(!request.CostId.IsEmpty(), record => record.CostId == request.CostId) .Where(record => record.Type == BalanceRecordTypeEnumType.Out) .OrderBy(record => record.CreateTime, OrderByType.Desc) .ToListAsync(); var lst = new List(); foreach (var departmentGroup in paeginfos.GroupBy(record => record.DepartmentNo)) { // 每个部门 var obj = new BalanceRecordSummaryRespones { DepartmentNo = departmentGroup.Key, CostId = request.CostId, OriginTenantId = "" }; // 所有人次 var BreakfastNumberOfPeople = departmentGroup.Count(x => x.ShiftType == ShiftEnumType.Breakfast); var LunchNumberOfPeople = departmentGroup.Count(x => x.ShiftType == ShiftEnumType.Lunch); var DinnerNumberOfPeople = departmentGroup.Count(x => x.ShiftType == ShiftEnumType.Dinner); var LateNightNumberOfPeople = departmentGroup.Count(x => x.ShiftType == ShiftEnumType.Nightsnack); //每个餐次人数 obj.BreakfastNumberOfPeople = departmentGroup.Where(x => x.ShiftType == ShiftEnumType.Breakfast).Select(x => x.UserNo).Distinct().Count(); obj.LunchNumberOfPeople = departmentGroup.Where(x => x.ShiftType == ShiftEnumType.Lunch).Select(x => x.UserNo).Distinct().Count(); obj.DinnerNumberOfPeople = departmentGroup.Where(x => x.ShiftType == ShiftEnumType.Dinner).Select(x => x.UserNo).Distinct().Count(); obj.LateNightNumberOfPeople = departmentGroup.Where(x => x.ShiftType == ShiftEnumType.Nightsnack).Select(x => x.UserNo).Distinct().Count(); //餐次金额 obj.BreakfastAmount = Math.Abs(departmentGroup.Where(x => x.ShiftType == ShiftEnumType.Breakfast).Sum(x => x.Amount)); obj.LunchAmount = Math.Abs(departmentGroup.Where(x => x.ShiftType == ShiftEnumType.Lunch).Sum(x => x.Amount)); obj.DinnerAmount = Math.Abs(departmentGroup.Where(x => x.ShiftType == ShiftEnumType.Dinner).Sum(x => x.Amount)); obj.LateNightAmount = Math.Abs(departmentGroup.Where(x => x.ShiftType == ShiftEnumType.Nightsnack).Sum(x => x.Amount)); // 每个餐次单价 obj.BreakfastPrice = BreakfastNumberOfPeople == 0 ? 0 : Math.Round(obj.BreakfastAmount / BreakfastNumberOfPeople, 2); obj.LunchPrice = LunchNumberOfPeople == 0 ? 0 : Math.Round(obj.LunchAmount / LunchNumberOfPeople, 2); obj.DinnerPrice = DinnerNumberOfPeople == 0 ? 0 : Math.Round(obj.DinnerAmount / DinnerNumberOfPeople, 2); obj.LateNightPrice = LateNightNumberOfPeople == 0 ? 0 : Math.Round(obj.LateNightAmount / LateNightNumberOfPeople, 2); // 总人数 总金额 obj.TotalNumberOfPeople = departmentGroup.Select(x => x.UserNo).Distinct().Count(); obj.TotalAmount = obj.BreakfastAmount + obj.LunchAmount + obj.DinnerAmount + obj.LateNightAmount; lst.Add(obj); } var departments = await _dbContext.Queryable().ToListAsync(); lst.ForEach(x => { x.DepartmentName = departments.Where(d => d.No == x.DepartmentNo).Select(d => d.Name).First(); }); // 分页操作 var startIndex = (request.PageIndex - 1) * request.PageSize; var pagedData = lst.Skip(startIndex).Take(request.PageSize).ToList(); var pagination = new Pagination { PageIndex = request.PageIndex, PageSize = request.PageSize, Total = lst.Count, // 使用原始列表的总数进行分页 Data = pagedData }; return pagination; } /// /// 消费汇总 根据人事范围 /// /// /// public async Task> BalanceRecordSummaryByTidAsync(BalanceRecordSummaryRequest request) { var paeginfos = await _dbContext.Queryable() .WhereIF(!request.DepartmentNo.IsEmpty(), record => record.DepartmentNo == request.DepartmentNo) .WhereIF(!request.UserCode.IsEmpty(), record => record.UserCode == request.UserCode) .WhereIF(!request.OriginTenantId.IsEmpty(), record => record.TenantId == request.OriginTenantId) .WhereIF(request.StartDatetime.HasValue, record => record.CostDateTime >= request.StartDatetime) .WhereIF(request.EndDatetime.HasValue, record => record.CostDateTime <= request.EndDatetime) .WhereIF(!request.CostId.IsEmpty(), record => record.CostId == request.CostId) .Where(record => record.Type == BalanceRecordTypeEnumType.Out) .OrderBy(record => record.CreateTime, OrderByType.Desc) .ToListAsync(); var lst = new List(); foreach (var originTenantIdGroup in paeginfos.GroupBy(record => record.OriginTenantId)) { // 每个人事范围 var obj = new BalanceRecordSummaryRespones { OriginTenantId = originTenantIdGroup.Key, CostId = request.CostId, DepartmentNo = "" }; // 所有人次 var BreakfastNumberOfPeople = originTenantIdGroup.Count(x => x.ShiftType == ShiftEnumType.Breakfast); var LunchNumberOfPeople = originTenantIdGroup.Count(x => x.ShiftType == ShiftEnumType.Lunch); var DinnerNumberOfPeople = originTenantIdGroup.Count(x => x.ShiftType == ShiftEnumType.Dinner); var LateNightNumberOfPeople = originTenantIdGroup.Count(x => x.ShiftType == ShiftEnumType.Nightsnack); //每个餐次人数 obj.BreakfastNumberOfPeople = originTenantIdGroup.Where(x => x.ShiftType == ShiftEnumType.Breakfast).Select(x => x.UserNo).Distinct().Count(); obj.LunchNumberOfPeople = originTenantIdGroup.Where(x => x.ShiftType == ShiftEnumType.Lunch).Select(x => x.UserNo).Distinct().Count(); obj.DinnerNumberOfPeople = originTenantIdGroup.Where(x => x.ShiftType == ShiftEnumType.Dinner).Select(x => x.UserNo).Distinct().Count(); obj.LateNightNumberOfPeople = originTenantIdGroup.Where(x => x.ShiftType == ShiftEnumType.Nightsnack).Select(x => x.UserNo).Distinct().Count(); //餐次金额 obj.BreakfastAmount = Math.Abs(originTenantIdGroup.Where(x => x.ShiftType == ShiftEnumType.Breakfast).Sum(x => x.Amount)); obj.LunchAmount = Math.Abs(originTenantIdGroup.Where(x => x.ShiftType == ShiftEnumType.Lunch).Sum(x => x.Amount)); obj.DinnerAmount = Math.Abs(originTenantIdGroup.Where(x => x.ShiftType == ShiftEnumType.Dinner).Sum(x => x.Amount)); obj.LateNightAmount = Math.Abs(originTenantIdGroup.Where(x => x.ShiftType == ShiftEnumType.Nightsnack).Sum(x => x.Amount)); // 每个餐次单价 obj.BreakfastPrice = BreakfastNumberOfPeople == 0 ? 0 : Math.Round(obj.BreakfastAmount / BreakfastNumberOfPeople, 2); obj.LunchPrice = LunchNumberOfPeople == 0 ? 0 : Math.Round(obj.LunchAmount / LunchNumberOfPeople, 2); obj.DinnerPrice = DinnerNumberOfPeople == 0 ? 0 : Math.Round(obj.DinnerAmount / DinnerNumberOfPeople, 2); obj.LateNightPrice = LateNightNumberOfPeople == 0 ? 0 : Math.Round(obj.LateNightAmount / LateNightNumberOfPeople, 2); // 总人数 总金额 obj.TotalNumberOfPeople = originTenantIdGroup.Select(x => x.UserNo).Distinct().Count(); obj.TotalAmount = obj.BreakfastAmount + obj.LunchAmount + obj.DinnerAmount + obj.LateNightAmount; lst.Add(obj); } // 分页操作 var startIndex = (request.PageIndex - 1) * request.PageSize; var pagedData = lst.Skip(startIndex).Take(request.PageSize).ToList(); var pagination = new Pagination { PageIndex = request.PageIndex, PageSize = request.PageSize, Total = lst.Count, // 使用原始列表的总数进行分页 Data = pagedData }; return pagination; } /// /// 用餐分析 /// /// /// public async Task> BalanceRecordAnalysisAsync(BalanceRecordAnalysisRequest request) { var pageinfo = await _dbContext.Queryable() .WhereIF(request.StartDatetime.HasValue, record => record.CostDateTime >= request.StartDatetime) .WhereIF(request.EndDatetime.HasValue, record => record.CostDateTime <= request.EndDatetime) .WhereIF(request.BusinessPlaceCode.HasValue, record => record.BusinessPlaceCode == request.BusinessPlaceCode) .Where(record => record.Type == BalanceRecordTypeEnumType.Out) .ToListAsync(); var lst = new List(); foreach (var first in pageinfo.GroupBy(record => record.CostDateTime.ToString("yyyy-MM-dd"))) { var obj = new BalanceRecordAnalysisRespones() { CostDate = DateOnly.FromDateTime(Convert.ToDateTime(first.Key)), }; //每个餐次人数 obj.BreakfastNumberOfPeople = first.Where(x => x.ShiftType == ShiftEnumType.Breakfast).Select(x => x.UserNo).Distinct().Count(); obj.LunchNumberOfPeople = first.Where(x => x.ShiftType == ShiftEnumType.Lunch).Select(x => x.UserNo).Distinct().Count(); obj.DinnerNumberOfPeople = first.Where(x => x.ShiftType == ShiftEnumType.Lunch).Select(x => x.UserNo).Distinct().Count(); obj.LateNightNumberOfPeople = first.Where(x => x.ShiftType == ShiftEnumType.Nightsnack).Select(x => x.UserNo).Distinct().Count(); obj.TotalNumberOfPeople = first.Where(x => x.CostDate.ToString("yyyy-MM-dd") == first.Key).Select(x => x.UserNo).Distinct().Count(); lst.Add(obj); } // 分页操作 var startIndex = (request.PageIndex - 1) * request.PageSize; var pagedData = lst.Skip(startIndex).Take(request.PageSize).ToList(); var pagination = new Pagination { PageIndex = request.PageIndex, PageSize = request.PageSize, Total = lst.Count, // 使用原始列表的总数进行分页 Data = pagedData }; return pagination; } public async Task> GetPageByDeviceUniqueNoAsync(BalanceRecordPageByDeviceUniqueNoRequest request) { var now = DateTime.Now; var start = DateTime.Today; var end = new DateTime(now.Year, now.Month, now.Day, 23, 59, 59); if (request.SearchDate.HasValue) { now = request.SearchDate.Value; start = new DateTime(now.Year, now.Month, now.Day); end = new DateTime(now.Year, now.Month, now.Day, 23, 59, 59); } var device = await _dbContext.Queryable() .Where(x => x.UniqueNo == request.DeviceUniqueNo || x.Code == Guid.Parse(request.DeviceUniqueNo)) .FirstAsync(); if (device == null) { return new Pagination() { Data = new List() }; } var page = await _dbContext.Queryable() .LeftJoin((record, ga) => record.UserNo == ga.No) .LeftJoin((record, ga, department) => ga.DepartmentNo == department.No) .LeftJoin((record, ga, department, bplace) => record.BusinessPlaceCode == bplace.Code) .LeftJoin((record, ga, department, bplace, bshift) => record.BusinessShiftCode == bshift.Code) .LeftJoin((record, ga, department, bplace, bshift, type) => record.BusinessShiftCode.ToString() == type.Code) .WhereIF(request.SearchDate.HasValue, record => record.CostDate >= start) .WhereIF(request.SearchDate.HasValue, record => record.CostDate <= end) .Where(record => record.TenantId == device.TenantId && (record.DeviceUniqueNo == device.Code.ToString() || record.DeviceUniqueNo == device.UniqueNo)) .Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid) .OrderBy(record => record.CreateTime, OrderByType.Desc) .Select((record, ga, department, bplace, bshift, type) => new BalanceRecordResponse { Id = record.Id, Amount = record.Amount, BusinessPlaceCode = record.BusinessPlaceCode, BusinessShiftCode = record.BusinessShiftCode, CostDate = record.CostDate, CostId = record.CostId, DepartmentNo = record.DepartmentNo, DeviceInfo = record.DeviceUniqueNo, IP = record.IP, UserNo = record.UserNo, UserCode = record.UserCode, Type = record.Type, SubsidiesFromMonth = record.SubsidiesFromMonth, Status = record.Status, Source = record.Source, No = record.No, IsCostCrossTenant = record.IsCostCrossTenant, OriginTenantId = record.OriginTenantId, Name = record.Name, DepartmentName = department.Name, BusinessPlaceName = bplace.Name, BusinessShiftName = type.Display, CostDateTime = record.CostDateTime }).ToPageListAsync(request); //消费总金额 var sum = await _dbContext.Queryable() .WhereIF(request.SearchDate.HasValue, record => record.CostDate >= start) .WhereIF(request.SearchDate.HasValue, record => record.CostDate <= end) .Where(record => record.TenantId == device.TenantId || record.DeviceUniqueNo == device.Code.ToString() || record.DeviceUniqueNo == device.UniqueNo) .Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid) .SumAsync(record => SqlFunc.Abs(SqlFunc.IsNull(record.Amount, 0))); page.Data.ForEach(x => x.Sum = sum); return page; } public async Task> GetPageByUserAsync(BalanceRecordUserPageRequest request) { //当前用户 var userId = _currentUser.GetIntSubjectId(); var page = await _dbContext.Queryable() .LeftJoin((record, ga) => record.UserNo == ga.No) .LeftJoin((record, ga, department) => ga.DepartmentNo == department.No) .LeftJoin((record, ga, department, bplace) => record.BusinessPlaceCode == bplace.Code) .LeftJoin((record, ga, department, bplace, bshiftR) => bplace.Code == bshiftR.PlaceCode) .LeftJoin((record, ga, department, bplace, bshiftR, shift) => shift.Code == bshiftR.ShiftCode) .WhereIF(request.SearchDateTimePeriod?.Start.HasValue == true, record => record.CostDate >= request.SearchDateTimePeriod.Start) .WhereIF(request.SearchDateTimePeriod?.End.HasValue == true, record => record.CostDate <= request.SearchDateTimePeriod.End) .WhereIF(request.ApplicationType.HasValue, record => record.ApplicationType == request.ApplicationType) .Where((record, ga) => ga.IdentityUserId == userId) .OrderBy(record => record.CreateTime, OrderByType.Desc) .Select((record, ga, department, bplace, bshiftR, shift) => new BalanceRecordUserResponse { Id = record.Id, Amount = record.Amount, Type = record.Type, Status = record.Status, Source = record.Source, No = record.No, BusinessPlaceName = bplace.Name, BusinessShiftName = shift.Name, CostDateTime = record.CostDateTime, ApplicationType = record.ApplicationType, }) .ToPageListAsync(request); return page; } public async Task ObsoluteAsync(BalanceRecordObsoluteRequest request) { var balanceRecord = await _dbContext.Queryable().Where(x => x.Id == request.Id).SingleAsync(); balanceRecord.ThrowIfNull("记录不存在"); (balanceRecord.Type != BalanceRecordTypeEnumType.Out).ThrowIfTrue("非消费记录,无法操作"); balanceRecord.Status = BalanceRecordStatusEnumType.Obsolute; balanceRecord.Remark = request.Reason; await ContinueUpdateAsync(async () => { //重算金额 var canteenUser = await _dbContext.Queryable().Where(x => x.UserNo == balanceRecord.UserNo).SingleAsync(); //金额 + canteenUser.Balance += Math.Abs(balanceRecord.Amount); var effect = await _dbContext.Updateable() .SetColumns(x => x.Balance == canteenUser.Balance) .SetColumns(x => x.Version == x.Version + 1) .Where(x => x.UserNo == balanceRecord.UserNo && x.Version == canteenUser.Version) .ExecuteCommandAsync(); if (effect <= 0) throw new VersionExceptions("更新版本冲突"); await _dbContext.UpdateAsync(balanceRecord); }, 5); } public async Task GetConsumeNumberAsync() { var devices = await _dbContext.Queryable() .Where(x => x.Type == DeviceTypeEnumType.Meal) .ToListAsync(); var offCount = await GetOfflineDevicesCount(devices); var places = await _dbContext.Queryable() .Where(x => x.Status == CanteenBusinessPlaceStatusEnumType.Opened) .ToListAsync(); //所有消费数据 var bs = await _dbContext.Queryable() .Where(x => x.Type == BalanceRecordTypeEnumType.Out) .ToListAsync(); //可消费人数 var consumerable = bs.Select(x => x.UserCode).Distinct().Count(); var dailyNumber = SameDay(bs, ""); //消费走势 var months = await GetConsumptionTrendsAsync(ConsumptionTrendEnumType.Month); var days = await GetConsumptionTrendsAsync(ConsumptionTrendEnumType.Day); var res = new ConsumeNumberResponse { Total = devices.Count, OffNumber = offCount.Count, PlaceNumber = places.Count, ConsumerableNumber = consumerable, DailyNumber = dailyNumber, Days = days, Months = months }; return res; } /// /// 获取单日消费数据 /// /// /// /// private int SameDay(List bs, string userCode) { var time = DateTime.Now.ToString("yyyy-MM-dd"); var b = userCode.IsEmpty(); //当日消费数据 var monthbs = bs .Where(x => x.CostDateTime.ToString("yyyy-MM-dd") == time) .WhereIF(!userCode.IsEmpty(), x => x.UserCode == userCode); //当日消费额 var monthlySpending = monthbs.Sum(x => x.Amount); //当日消费人数 var monthlyCount = monthbs.Select(x => x.UserCode).Distinct().Count(); var dailyNumber = monthlyCount != 0 ? Math.Abs((int)Math.Ceiling(monthlySpending / monthlyCount)) : 0; return dailyNumber; } public async Task> GetSpendingDetailsAsync(SpendingDetailRequest request) { var brs = await _dbContext .Queryable() .Where(x => x.Type == BalanceRecordTypeEnumType.Out) .ToListAsync(); var codes = brs.Select(x => x.UserCode).ToList().Distinct().ToList(); var lst = new List(); foreach (var code in codes) { var br = brs.Where(x => x.UserCode == code).FirstOrDefault(); var res = br.Adapt(); lst.Add(res); } // 分页操作 var startIndex = (request.PageIndex - 1) * request.PageSize; var pagedData = lst.Skip(startIndex).Take(request.PageSize).ToList(); var pagination = new Pagination { PageIndex = request.PageIndex, PageSize = request.PageSize, Total = lst.Count, // 使用原始列表的总数进行分页 Data = pagedData }; return pagination; } public async Task> AverageDailyAsync(AverageDailyRequest request) { //所有消费数据 var brs = await _dbContext.Queryable() .Where(x => x.Type == BalanceRecordTypeEnumType.Out) .ToListAsync(); var codes = brs.Select(x => x.UserCode).ToList().Distinct().ToList(); var lst = new List(); foreach (var code in codes) { var br = brs.Where(x => x.UserCode == code).FirstOrDefault(); var res = br.Adapt(); var dailyNumber = SameDay(brs, code); res.AverageAmount = dailyNumber; lst.Add(res); } // 分页操作 var startIndex = (request.PageIndex - 1) * request.PageSize; var pagedData = lst.Skip(startIndex).Take(request.PageSize).ToList(); var pagination = new Pagination { PageIndex = request.PageIndex, PageSize = request.PageSize, Total = lst.Count, // 使用原始列表的总数进行分页 Data = pagedData }; return pagination; } public async Task> GetConsumeDeviceAsync(GetConsumeDeviceRequest request) { if (request.IsOff) { //消费机离线设备 var devices = await _dbContext.Queryable() .Where(x => x.Type == DeviceTypeEnumType.Meal) .ToListAsync(); var offs = await GetOfflineDevicesCount(devices); var offUniqueNos = offs.Select(x => x.UniqueNo).ToList(); var offpage = await _dbContext.Queryable() .LeftJoin((d, dt) => d.TemplateCode == dt.Code) .Where(d => offUniqueNos.Contains(d.UniqueNo)) .Select((d, dt) => new DevicePageResponse { FuncsStr = d.Funcs.ToString(), Brand = dt.Brand, Type = d.Type, }, true) .ToPageListAsync(request); return offpage; } //消费机总数 var page = await _dbContext.Queryable() .LeftJoin((d, dt) => d.TemplateCode == dt.Code) .Where(d => d.Type == DeviceTypeEnumType.Meal) .Select((d, dt) => new DevicePageResponse { FuncsStr = d.Funcs.ToString(), Brand = dt.Brand, Type = d.Type, }, true) .ToPageListAsync(request); return page; } public async Task> GetBalanceOfMealSupplementRecordByUser(BalanceRecordByUserRequest request) { var page = await _dbContext.Queryable() .Where(x => x.Source == BalanceRecordSourceEnumType.LocalTenantSubsidies || x.Source == BalanceRecordSourceEnumType.OtherTenantSubsidies) .Where(x => x.UserNo == request.UserNo) .Select() .ToPageListAsync(request); return page; } /// /// 获取离线设备 /// /// /// private async Task> GetOfflineDevicesCount(List devices) { var now = DateTime.Now; var deviceUniqueNos = devices.Select(x => x.UniqueNo).ToList(); var deviceRegistries = await _dbContext.Queryable() .LeftJoin((x, d) => x.DeviceUniqueNo == d.UniqueNo) .Where(x => deviceUniqueNos.Contains(x.DeviceUniqueNo)) .Select((x, d) => new { d.UniqueNo, d.HeartbeatInterval, x.LastHeartbeatTime }) .ToListAsync(); var OnlineDevices = deviceRegistries .Where(x => { if (x.HeartbeatInterval <= 0) { return true; } return x.LastHeartbeatTime.AddSeconds(x.HeartbeatInterval * 3) >= now; }) .Select(x => new { x.UniqueNo, }) .ToList(); var onlineUniqueNos = new List(); OnlineDevices.ForEach(x => onlineUniqueNos.Add(x.UniqueNo)); var offUniqueNos = deviceUniqueNos.Except(onlineUniqueNos).ToList(); var list = devices.Where(x => offUniqueNos.Contains(x.UniqueNo)).ToList(); return list; } private async Task> GetConsumptionTrendsAsync(ConsumptionTrendEnumType type) { var bs = await _dbContext.Queryable() .Where(x => x.Type == BalanceRecordTypeEnumType.Out) .ToListAsync(); //消费总额 var totalAmount = Math.Round(Math.Abs(bs.Sum(x => x.Amount)), 2); var list = new List(); if (type == ConsumptionTrendEnumType.Month) { //月与总额对比 var months = GetMonthsOfYear(); foreach (var month in months) { var currentAmount = Math.Round(Math.Abs(bs.Where(x => x.CostDateTime.ToString("yyyy-MM") == month) .Sum(x => x.Amount)), 2); var res = new ConsumptionTrendResponse { DateTime = month, CurrentAmount = currentAmount, TotalAmount = totalAmount }; list.Add(res); } } else { //日与总额对比 var days = GetDaysOfMonth(); foreach (var day in days) { var currentAmount = Math.Round(Math.Abs(bs.Where(x => x.CostDateTime.ToString("yyyy-MM-dd") == day) .Sum(x => x.Amount)), 2); var res = new ConsumptionTrendResponse { DateTime = day, CurrentAmount = currentAmount, TotalAmount = totalAmount }; list.Add(res); } } return list; } /// /// 获取当前年所有月 /// /// private List GetMonthsOfYear() { List months = new List(); // 获取当前年份 int year = DateTime.Now.Year; // 遍历12个月份并添加到列表中 for (int month = 1; month <= 12; month++) { DateTime monthDate = new DateTime(year, month, 1); months.Add(monthDate.ToString("yyyy-MM")); } return months; } /// /// 获取当前月所有天 /// /// private List GetDaysOfMonth() { List days = new List(); // 获取当前年份和月份 int year = DateTime.Now.Year; int month = DateTime.Now.Month; // 获取当前月份的第一天和最后一天 DateTime firstDayOfMonth = new DateTime(year, month, 1); DateTime lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1); // 遍历当前月的所有日期并添加到列表中 for (DateTime date = firstDayOfMonth; date <= lastDayOfMonth; date = date.AddDays(1)) { days.Add(date.ToString("yyyy-MM-dd")); } return days; } //************************************************************** help methods ****************************************************************** private async Task ContinueUpdateAsync(Func func, int retry) { for (int i = 0; i < retry; i++) { try { await func(); return; } catch (Exception ex) when (ex is VersionExceptions) { _logger.LogWarning(ex, ex.Message); } catch (Exception) { throw; } } throw new UserFriendlyException("操作失败,请重试"); } }