using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NCC.Extend.Entitys.Enum;
using NCC.Extend.Entitys.lq_attendance_group;
using NCC.Extend.Entitys.lq_attendance_record;
using NCC.Extend.Entitys.lq_attendance_summary;
using NCC.Extend.Entitys.lq_mdxx;
using NCC.System.Entitys.Permission;
using SqlSugar;
namespace NCC.Extend
{
///
/// 月度考勤报表 / 考勤汇总共用的「当月在职」人员行(与花名册、Skill historical-on-job-inference 一致)。
///
public sealed class AttendanceMonthEligibleUserLine
{
public string UserId { get; set; }
public string EmployeeName { get; set; }
public string StoreId { get; set; }
public string StoreName { get; set; }
public string AttendanceGroupId { get; set; }
public string GroupName { get; set; }
}
///
/// 按自然月查询「当月在职口径」人员(与 LqEmployeeRosterService、月度考勤矩阵相同 JOIN 条件)。
///
///
/// 规则:该月存在有效考勤汇总且 F_EmployeeStatus = 1 则入选;无汇总且非未来月时按主档
/// 入职不晚于月末、离职为空或≥月初;未来月仅认汇总(仅第一分支成立)。
///
public static class AttendanceMonthOnJobUserQuery
{
///
/// 查询指定年月的在职口径人员列表。
///
/// 数据库客户端
/// 年
/// 月
/// 该月 1 日 00:00:00
/// 该月最后一天 23:59:59
/// 是否为未来月(相对当前系统日期)
/// 可选,姓名/账号/门店/分组模糊
/// 可选考勤分组
public static async Task> QueryEligibleUsersAsync(
ISqlSugarClient db,
int year,
int month,
DateTime monthStart,
DateTime monthLast,
bool isFutureMonth,
string keyword,
string attendanceGroupId)
{
var kw = keyword?.Trim();
var lines = await db.Queryable(
(u, s, g, summ) => new JoinQueryInfos(
JoinType.Left, s.Id == u.Mdid,
JoinType.Left, g.Id == s.AttendanceGroupId,
JoinType.Left,
summ.UserId == u.Id && summ.Year == year && summ.Month == month &&
summ.IsEffective == StatusEnum.有效.GetHashCode()))
.Where((u, s, g, summ) => u.DeleteMark == null)
.Where((u, s, g, summ) =>
(!SqlFunc.IsNullOrEmpty(summ.Id) && summ.EmployeeStatus == 1)
|| (!isFutureMonth
&& SqlFunc.IsNullOrEmpty(summ.Id)
&& u.EntryDate != null
&& u.EntryDate <= monthLast
&& (u.LeaveDate == null || u.LeaveDate >= monthStart)))
.WhereIF(!string.IsNullOrWhiteSpace(attendanceGroupId),
(u, s, g, summ) => s.AttendanceGroupId == attendanceGroupId)
.WhereIF(!string.IsNullOrWhiteSpace(kw), (u, s, g, summ) =>
SqlFunc.Contains(SqlFunc.IsNull(u.RealName, ""), kw) ||
SqlFunc.Contains(SqlFunc.IsNull(u.Account, ""), kw) ||
SqlFunc.Contains(SqlFunc.IsNull(s.Dm, ""), kw) ||
SqlFunc.Contains(SqlFunc.IsNull(g.GroupName, ""), kw))
.Select((u, s, g, summ) => new AttendanceMonthEligibleUserLine
{
UserId = u.Id,
EmployeeName = u.RealName,
StoreId = u.Mdid,
StoreName = s.Dm,
AttendanceGroupId = s.AttendanceGroupId,
GroupName = g.GroupName
})
.ToListAsync();
return lines
.OrderBy(x => x.StoreName ?? "")
.ThenBy(x => x.GroupName ?? "")
.ThenBy(x => x.EmployeeName ?? "")
.ToList();
}
///
/// 月度矩阵展示用:在「在职口径」名单之外,把该月已在 lq_attendance_record 中有有效行,
/// 但未被 选中的员工补进列表(常见:主档入职日为未填、与花名册口径不一致等),
/// 避免定时补 INSERT 后管理端仍显示无数据。
///
public static async Task> MergeWithRecordOnlyHoldersAsync(
ISqlSugarClient db,
DateTime monthStart,
DateTime monthEnd,
IReadOnlyCollection baseEligible,
string keyword,
string attendanceGroupId)
{
var baseIds = baseEligible
.Select(x => x.UserId)
.Where(x => !string.IsNullOrWhiteSpace(x))
.Distinct()
.ToList();
var orphanIds = await db.Queryable()
.Where(x => x.IsEffective == StatusEnum.有效.GetHashCode())
.Where(x => x.AttendanceDate >= monthStart && x.AttendanceDate < monthEnd)
.Where(x => !string.IsNullOrWhiteSpace(x.UserId))
.Where(baseIds.Count > 0 ? (x => !baseIds.Contains(x.UserId)) : (x => true))
.Select(x => x.UserId)
.Distinct()
.ToListAsync();
if (orphanIds == null || orphanIds.Count == 0)
{
return baseEligible.ToList();
}
var kw = keyword?.Trim();
var extra = await db.Queryable(
(u, s, g) => new JoinQueryInfos(
JoinType.Left, s.Id == u.Mdid,
JoinType.Left, g.Id == s.AttendanceGroupId))
.Where((u, s, g) => u.DeleteMark == null)
.Where((u, s, g) => orphanIds.Contains(u.Id))
.WhereIF(!string.IsNullOrWhiteSpace(attendanceGroupId),
(u, s, g) => s.AttendanceGroupId == attendanceGroupId)
.WhereIF(!string.IsNullOrWhiteSpace(kw), (u, s, g) =>
SqlFunc.Contains(SqlFunc.IsNull(u.RealName, ""), kw) ||
SqlFunc.Contains(SqlFunc.IsNull(u.Account, ""), kw) ||
SqlFunc.Contains(SqlFunc.IsNull(s.Dm, ""), kw) ||
SqlFunc.Contains(SqlFunc.IsNull(g.GroupName, ""), kw))
.Select((u, s, g) => new AttendanceMonthEligibleUserLine
{
UserId = u.Id,
EmployeeName = u.RealName,
StoreId = u.Mdid,
StoreName = s.Dm,
AttendanceGroupId = s.AttendanceGroupId,
GroupName = g.GroupName
})
.ToListAsync();
return baseEligible
.Concat(extra)
.OrderBy(x => x.StoreName ?? "")
.ThenBy(x => x.GroupName ?? "")
.ThenBy(x => x.EmployeeName ?? "")
.ToList();
}
}
}