using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using NCC.Extend.Entitys.lq_attendance_record; using NCC.Extend.Entitys.lq_attendance_summary; using NCC.Extend.Entitys.lq_employee_store_assignment; using NCC.Extend.Entitys.lq_hytk_jksyj; using NCC.Extend.Entitys.lq_hytk_kjbsyj; using NCC.Extend.Entitys.lq_jinsanjiao_user; using NCC.Extend.Entitys.lq_kd_jksyj; using NCC.Extend.Entitys.lq_kd_kjbsyj; using NCC.Extend.Entitys.lq_person_times_record; using NCC.Extend.Entitys.lq_salary_statistics; using NCC.Extend.Entitys.lq_xh_hyhk; using NCC.Extend.Entitys.lq_xh_jksyj; using NCC.Extend.Entitys.lq_xh_kjbsyj; using NCC.Extend.Entitys.lq_assistant_salary_statistics; using NCC.Extend.Entitys.lq_business_unit_manager_salary_statistics; using NCC.Extend.Entitys.lq_director_salary_statistics; using NCC.Extend.Entitys.lq_major_project_director_salary_statistics; using NCC.Extend.Entitys.lq_major_project_teacher_salary_statistics; using NCC.Extend.Entitys.lq_store_manager_salary_statistics; using NCC.Extend.Entitys.lq_tech_general_manager_salary_statistics; using NCC.Extend.Entitys.lq_tech_teacher_salary_statistics; using NCC.System.Entitys.Permission; using SqlSugar; namespace NCC.Extend { /// /// 统计自然月内「有业务事实」的员工(BASE_USER.F_Id),用于月中离职仍参与当月算薪、以及各模块复用名单口径。 /// public static class LqMonthlyEmployeeFactHelper { private const int KeyResolveChunkSize = 500; /// /// 汇总指定年月中,在考勤/业绩/消耗/金三角/工资归档等任一来源出现过的用户主键(已解析为 BASE_USER.F_Id)。 /// jkszh/kjblszh 等与账号或主键混存的字段会按 Id 或 Account 匹配用户行(未软删)。 /// public static async Task> GetUserIdsWithMonthBusinessFactsAsync( ISqlSugarClient db, int year, int month) { if (year < 1990 || year > 2100 || month < 1 || month > 12) { return new List(); } var startDate = new DateTime(year, month, 1); var endDate = startDate.AddMonths(1).AddDays(-1); var monthStr = $"{year}{month:D2}"; var endOpen = endDate.AddDays(1); var rawKeys = new HashSet(StringComparer.Ordinal); void AddKey(string k) { if (!string.IsNullOrWhiteSpace(k)) { rawKeys.Add(k.Trim()); } } // 与算薪扩大候选一致 foreach (var id in await LqSalaryUserSnapshotHelper.GetSalaryCandidateUserIdsAsync(db, startDate, endDate, year, month)) { AddKey(id); } var attUserIds = await db.Queryable() .Where(x => x.AttendanceDate >= startDate.Date && x.AttendanceDate <= endDate.Date && x.IsEffective == 1) .Select(x => x.UserId) .ToListAsync(); foreach (var id in attUserIds) { AddKey(id); } var personIds = await db.Queryable() .Where(x => x.WorkMonth == monthStr && x.IsEffective == 1) .Select(x => x.PersonId) .ToListAsync(); foreach (var id in personIds) { AddKey(id); } var jsUserIds = await db.Queryable() .Where(x => x.Month == monthStr && x.DeleteMark == 0) .Select(x => x.UserId) .ToListAsync(); foreach (var id in jsUserIds) { AddKey(id); } void AddJkszhBatch(List zhList) { foreach (var z in zhList) { AddKey(z); } } AddJkszhBatch(await db.Queryable() .Where(x => x.Yjsj >= startDate && x.Yjsj < endOpen && x.IsEffective == 1) .Select(x => x.Jkszh) .ToListAsync()); AddJkszhBatch(await db.Queryable() .Where(x => x.Yjsj >= startDate && x.Yjsj < endOpen && x.IsEffective == 1) .Select(x => x.Jkszh) .ToListAsync()); AddJkszhBatch(await db.Queryable() .Where(x => x.Tksj >= startDate && x.Tksj < endOpen && x.IsEffective == 1) .Select(x => x.Jkszh) .ToListAsync()); AddJkszhBatch(await db.Queryable() .Where(x => x.Yjsj >= startDate && x.Yjsj < endOpen && x.IsEffective == 1) .Select(x => x.Kjblszh) .ToListAsync()); AddJkszhBatch(await db.Queryable( (kj, hk) => kj.Glkdbh == hk.Id && hk.IsEffective == 1) .Where((kj, hk) => kj.IsEffective == 1 && hk.Hksj >= startDate && hk.Hksj < endOpen) .Select((kj, hk) => kj.Kjblszh) .ToListAsync()); AddJkszhBatch(await db.Queryable() .Where(x => x.Tksj >= startDate && x.Tksj < endOpen && x.IsEffective == 1) .Select(x => x.Kjblszh) .ToListAsync()); // 各岗位工资归档(已算过薪的月份仍应出现在「有事实」名单中,便于补算/核对) AddJkszhBatch(await db.Queryable() .Where(x => x.StatisticsMonth == monthStr) .Select(x => x.EmployeeId) .ToListAsync()); AddJkszhBatch(await db.Queryable() .Where(x => x.StatisticsMonth == monthStr) .Select(x => x.EmployeeId) .ToListAsync()); AddJkszhBatch(await db.Queryable() .Where(x => x.StatisticsMonth == monthStr) .Select(x => x.EmployeeId) .ToListAsync()); AddJkszhBatch(await db.Queryable() .Where(x => x.StatisticsMonth == monthStr) .Select(x => x.EmployeeId) .ToListAsync()); AddJkszhBatch(await db.Queryable() .Where(x => x.StatisticsMonth == monthStr) .Select(x => x.EmployeeId) .ToListAsync()); AddJkszhBatch(await db.Queryable() .Where(x => x.StatisticsMonth == monthStr) .Select(x => x.EmployeeId) .ToListAsync()); AddJkszhBatch(await db.Queryable() .Where(x => x.StatisticsMonth == monthStr) .Select(x => x.EmployeeId) .ToListAsync()); AddJkszhBatch(await db.Queryable() .Where(x => x.StatisticsMonth == monthStr) .Select(x => x.EmployeeId) .ToListAsync()); AddJkszhBatch(await db.Queryable() .Where(x => x.StatisticsMonth == monthStr) .Select(x => x.EmployeeId) .ToListAsync()); var resolved = await ResolveKeysToUserIdsAsync(db, rawKeys); return resolved.ToList(); } /// /// 将 jkszh/账号/主键等字符串解析为未软删用户的 F_Id。 /// public static async Task> ResolveKeysToUserIdsAsync(ISqlSugarClient db, IEnumerable rawKeys) { var set = new HashSet(StringComparer.Ordinal); if (rawKeys == null) { return set; } var keys = rawKeys.Where(k => !string.IsNullOrWhiteSpace(k)).Select(k => k.Trim()).Distinct().ToList(); for (var i = 0; i < keys.Count; i += KeyResolveChunkSize) { var chunk = keys.Skip(i).Take(KeyResolveChunkSize).ToList(); var ids = await db.Queryable() .Where(u => u.DeleteMark == null) .Where(u => chunk.Contains(u.Id) || chunk.Contains(u.Account)) .Select(u => u.Id) .ToListAsync(); foreach (var id in ids) { if (!string.IsNullOrEmpty(id)) { set.Add(id); } } } return set; } } }