From 910e21a04974e54a6f54c777b4957f6db31e1bf3 Mon Sep 17 00:00:00 2001 From: “wangming” <“wangming@antissoft.com”> Date: Tue, 2 Dec 2025 22:03:30 +0800 Subject: [PATCH] 修复开单记录汇总筛选逻辑:当传入筛选条件但无匹配数据时返回空结果,而不是所有记录 --- netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdDeductinfo/LqKdDeductinfoListOutput.cs | 15 +++++++++++++++ netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs | 630 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs | 2 +- netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs | 80 ++++++++++++++++++++++++++++++++++++++++++-------------------------------------- sql/修复人次记录HasBilling字段.sql | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 项目信息-薪酬规则与名词解释.md | 4 ++-- 6 files changed, 164 insertions(+), 614 deletions(-) create mode 100644 sql/修复人次记录HasBilling字段.sql diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdDeductinfo/LqKdDeductinfoListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdDeductinfo/LqKdDeductinfoListOutput.cs index 27b9c2b..f1de2ac 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdDeductinfo/LqKdDeductinfoListOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKdDeductinfo/LqKdDeductinfoListOutput.cs @@ -95,5 +95,20 @@ namespace NCC.Extend.Entitys.Dto.LqKdDeductinfo /// 门店名称 /// public string StoreName { get; set; } + + /// + /// 时间期间(开单日期,用于时间范围筛选) + /// + public DateTime? TimePeriod { get; set; } + + /// + /// 开单类型(购买、赠送、体验等) + /// + public string BillingType { get; set; } + + /// + /// 合作机构 + /// + public string CooperationInstitution { get; set; } } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs index d36e815..69a0287 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs @@ -47,6 +47,7 @@ using NCC.Extend.Entitys.lq_mdxx; using NCC.Extend.Entitys.lq_card_transfer_log; using NCC.Extend.Entitys.Dto.LqDailyReport; using NCC.Extend.Entitys.lq_yyjl; +using NCC.Extend.Entitys.lq_hzf; namespace NCC.Extend.LqKdKdjlb { @@ -2322,9 +2323,9 @@ namespace NCC.Extend.LqKdKdjlb } #endregion - #region 获取门店某个时间段的开单记录汇总信息 + #region 获取门店某个时间段的开单记录汇总信息(台账) /// - /// 获取门店某个时间段的开单记录汇总信息 + /// 获取门店某个时间段的开单记录汇总信息(台账) /// /// 查询参数 /// 开单记录汇总信息 @@ -2368,12 +2369,15 @@ namespace NCC.Extend.LqKdKdjlb zdyj = it.Zdyj, sfyj = it.Sfyj, qk = it.Qk, + hgjg = it.Hgjg, + hgjgName = SqlFunc.Subqueryable().Where(x => x.Id == it.Hgjg).Select(x => x.Hzmc), kdhyc = SqlFunc.Subqueryable().Where(x => x.Id == it.Kdhy).Select(x => x.Khmc), kdhysjh = SqlFunc.Subqueryable().Where(x => x.Id == it.Kdhy).Select(x => x.Sjh), fkfs = it.Fkfs, // 付款方式 khly = it.Khly, // 客户来源 bz = it.Bz, // 备注 createTime = it.CreateTime + }) .ToListAsync(); @@ -2491,240 +2495,55 @@ namespace NCC.Extend.LqKdKdjlb }) .ToListAsync(); - // 构建按开单记录分组的详细数据 - var detailedRecords = billingRecords.Select(billing => new - { - // 基本信息 - date = billing.kdrq?.ToString("yyyy-MM-dd"), - customerName = billing.kdhyc, - customerPhone = billing.kdhysjh, - storeId = billing.djmd, - goldTriangle = billing.jsj, - customerType = billing.gjlx, - - // 品项分类 - purchasedItems = itemDetails.Where(x => x.glkdbh == billing.id && x.sourceType == "购买").Select(x => new - { - id = x.id, - itemName = x.pxmc, - itemCode = x.px, - price = x.pxjg, - totalPrice = x.totalPrice, - actualPrice = x.actualPrice, - projectNumber = x.projectNumber, - remark = x.remark, - itemCategory = x.itemCategory, - }).ToList(), - - giftedItems = itemDetails.Where(x => x.glkdbh == billing.id && x.sourceType == "赠送").Select(x => new - { - id = x.id, - itemName = x.pxmc, - itemCode = x.px, - price = x.pxjg, - totalPrice = x.totalPrice, - actualPrice = x.actualPrice, - projectNumber = x.projectNumber, - remark = x.remark, - itemCategory = x.itemCategory, - }).ToList(), - - experienceItems = itemDetails.Where(x => x.glkdbh == billing.id && x.sourceType == "体验").Select(x => new - { - id = x.id, - itemName = x.pxmc, - itemCode = x.px, - price = x.pxjg, - totalPrice = x.totalPrice, - actualPrice = x.actualPrice, - projectNumber = x.projectNumber, - remark = x.remark, - itemCategory = x.itemCategory, - }).ToList(), - - // 金额信息 - paidAmount = billing.sfyj, - debtAmount = billing.qk, - totalAmount = billing.zdyj, - - // 健康师信息 - healthTeachers = healthTeacherData.Where(x => x.glkdbh == billing.id).Select(x => new - { - teacherId = x.jks, - teacherName = x.jksxm, - teacherAccount = x.jkszh, - performance = x.jksyj, - performanceTime = x.yjsj, - itemDetailId = x.kdpxid, - goldTriangleId = x.jsj_id, - itemCategory = x.itemCategory, - itemId = x.itemId, - storeId = x.storeId, - itemName = x.itemName - }).ToList(), - - // 其他信息 - source = billing.khly, // 客户来源 - paymentMethod = billing.fkfs, // 支付方式 - remark = billing.bz, // 备注 - createTime = billing.createTime - }).OrderByDescending(x => x.date).ToList(); + // 根据筛选条件过滤开单记录 + // 收集所有需要匹配的开单ID(取交集) + var matchedBillingIds = new List(); + var hasFilterCondition = false; // 标记是否传入了筛选条件 - // 构建返回结果 - var result = new + // 如果传入了品项分类或品项筛选条件,收集匹配的开单ID + if (!string.IsNullOrEmpty(input.ItemCategory) || !string.IsNullOrEmpty(input.ItemId)) { - success = true, - data = new + hasFilterCondition = true; + var itemMatchedIds = itemDetails.Select(x => x.glkdbh).Distinct().ToList(); + if (matchedBillingIds.Any()) { - // 汇总统计 - summary = new - { - totalCount = billingRecords.Count, - totalAmount = billingRecords.Sum(x => x.zdyj), - totalPaidAmount = billingRecords.Sum(x => x.sfyj), - totalDebt = billingRecords.Sum(x => x.qk), - totalPurchasedItems = purchasedItems.Count, - totalGiftedItems = giftedItems.Count, - totalExperienceItems = experienceItems.Count, - totalHealthTeachers = healthTeacherData.GroupBy(x => x.jks).Count() - }, - // 详细记录列表 - records = detailedRecords - }, - message = "获取开单记录汇总信息成功" - }; - return result; - } - catch (Exception ex) - { - throw NCCException.Oh($"获取开单记录汇总信息失败:{ex.Message}"); - } - } - #endregion - - #region 获取门店某个时间段的开单记录汇总信息(备份) - /// - /// 获取门店某个时间段的开单记录汇总信息(备份) - /// - /// 查询参数 - /// 开单记录汇总信息 - [HttpGet("GetBillingRecordSummaryByStoreId_bak")] - public async Task GetBillingRecordSummaryByStoreId_bak([FromQuery] BillingRecordSummaryQueryInput input) - { - try - { - // 验证参数 - if (string.IsNullOrEmpty(input.StoreId)) - { - throw NCCException.Oh("门店ID不能为空"); + matchedBillingIds = matchedBillingIds.Intersect(itemMatchedIds).ToList(); + } + else + { + matchedBillingIds = itemMatchedIds; + } } - // 如果开始时间和结束时间为空,就默认是当月 - if (input.StartTime == null || input.EndTime == null) + // 如果传入了健康师筛选条件,收集匹配的开单ID + if (!string.IsNullOrEmpty(input.HealthCoachId)) { - input.StartTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1); - input.EndTime = DateTime.Now.AddDays(DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month)); - } - - // 查询开单记录 - var billingRecords = await _db.Queryable() - .Where(w => w.Djmd == input.StoreId && w.Kdrq >= input.StartTime && w.Kdrq <= input.EndTime && w.IsEffective == StatusEnum.有效.GetHashCode()) - .Select(it => new + hasFilterCondition = true; + var healthTeacherMatchedIds = healthTeacherData.Select(x => x.glkdbh).Distinct().ToList(); + if (matchedBillingIds.Any()) { - id = it.Id, - djmd = it.Djmd, - jsj = it.Jsj, - kdrq = it.Kdrq, - gjlx = it.Gjlx, - zdyj = it.Zdyj, - sfyj = it.Sfyj, - qk = it.Qk, - kdhyc = SqlFunc.Subqueryable().Where(x => x.Id == it.Kdhy).Select(x => x.Khmc), - kdhysjh = SqlFunc.Subqueryable().Where(x => x.Id == it.Kdhy).Select(x => x.Sjh), - fkfs = it.Fkfs, // 付款方式 - khly = it.Khly, // 客户来源 - bz = it.Bz, // 备注 - createTime = it.CreateTime - }) - .ToListAsync(); - - if (!billingRecords.Any()) - { - return new + matchedBillingIds = matchedBillingIds.Intersect(healthTeacherMatchedIds).ToList(); + } + else { - success = true, - data = new - { - billingSummary = new - { - totalCount = 0, - totalAmount = 0, - totalPaidAmount = 0, - totalDebt = 0, - billingRecords = new List() - }, - itemSummary = new - { - purchased = new { count = 0, totalAmount = 0, items = new List() }, - gifted = new { count = 0, totalAmount = 0, items = new List() }, - experience = new { count = 0, totalAmount = 0, items = new List() } - }, - healthTeacherSummary = new - { - totalCount = 0, - teachers = new List() - } - }, - message = "该时间段内无开单记录" - }; + matchedBillingIds = healthTeacherMatchedIds; + } } - var billingIds = billingRecords.Select(x => x.id).ToList(); - - // 查询品项明细,按F_SourceType分类 - var itemDetails = await _db.Queryable() - .Where(w => billingIds.Contains(w.Glkdbh) && w.IsEffective == StatusEnum.有效.GetHashCode()) - .Select(it => new + // 如果传入了筛选条件,必须过滤开单记录(即使没有匹配数据也要过滤,返回空结果) + if (hasFilterCondition) + { + if (matchedBillingIds.Any()) { - id = it.Id, - glkdbh = it.Glkdbh, - px = it.Px, - pxmc = it.Pxmc, - pxjg = it.Pxjg, - sourceType = it.SourceType, - totalPrice = it.TotalPrice, - actualPrice = it.ActualPrice, - projectNumber = it.ProjectNumber, - remark = it.Remark, - itemCategory = it.ItemCategory, - }) - .ToListAsync(); - - // 按来源类型分类品项 - var purchasedItems = itemDetails.Where(x => x.sourceType == "购买").ToList(); - var giftedItems = itemDetails.Where(x => x.sourceType == "赠送").ToList(); - var experienceItems = itemDetails.Where(x => x.sourceType == "体验").ToList(); - - // 查询健康师业绩数据 - var healthTeacherData = await _db.Queryable() - .Where(w => billingIds.Contains(w.Glkdbh) && w.IsEffective == StatusEnum.有效.GetHashCode()) - .Select(it => new + billingRecords = billingRecords.Where(x => matchedBillingIds.Contains(x.id)).ToList(); + } + else { - id = it.Id, - glkdbh = it.Glkdbh, - jks = it.Jks, - jksxm = it.Jksxm, - jkszh = it.Jkszh, - jksyj = it.Jksyj, - kdpxid = it.Kdpxid, - yjsj = it.Yjsj, - jsj_id = it.Jsj_id, - itemCategory = it.ItemCategory, - storeId = it.StoreId, - itemId = it.ItemId, - itemName = it.ItemName, - }) - .ToListAsync(); + // 传入了筛选条件但没有匹配数据,返回空结果 + billingRecords = billingRecords.Where(x => false).ToList(); + } + billingIds = billingRecords.Select(x => x.id).ToList(); + } // 构建按开单记录分组的详细数据 var detailedRecords = billingRecords.Select(billing => new @@ -2736,7 +2555,8 @@ namespace NCC.Extend.LqKdKdjlb storeId = billing.djmd, goldTriangle = billing.jsj, customerType = billing.gjlx, - + cooperationInstitution = billing.hgjg, + cooperationInstitutionName = billing.hgjgName, // 品项分类 purchasedItems = itemDetails.Where(x => x.glkdbh == billing.id && x.sourceType == "购买").Select(x => new { @@ -3647,351 +3467,6 @@ namespace NCC.Extend.LqKdKdjlb } #endregion - #region 门店整体统计表(备份) - /// - /// 门店整体统计表 - /// - /// - /// 统计每个健康师在指定时间周期内的各项数据指标 - /// 包括:邀约人数、预约人数、到店人数、开单人数、开单金额、消耗金额、人头、人次、消耗项目数 - /// - /// 示例请求: - /// ```json - /// { - /// "startTime": "2025-10-01", - /// "endTime": "2025-10-31", - /// "departmentId": "部门ID", - /// "storeId": "门店ID", - /// "employeeName": "健康师姓名" - /// } - /// ``` - /// - /// 参数说明: - /// - startTime: 开始时间(可选,默认为当月1号) - /// - endTime: 结束时间(可选,默认为当前时间) - /// - departmentId: 事业部ID(可选) - /// - storeId: 门店ID(可选) - /// - employeeName: 健康师姓名(可选) - /// - /// 返回字段说明: - /// - EmployeeId: 健康师ID - /// - EmployeeName: 健康师姓名 - /// - StoreId: 门店ID - /// - StoreName: 门店名称 - /// - DepartmentId: 事业部ID - /// - DepartmentName: 事业部名称 - /// - InviteCount: 邀约人数(按客户去重) - /// - AppointmentCount: 预约人数(按客户去重,无论预约状态) - /// - VisitCount: 到店人数(按客户去重,仅统计状态为'已确认'的预约) - /// - BillingCount: 开单人数(按开单记录去重) - /// - BillingAmount: 开单金额(开单业绩总金额) - /// - ConsumeAmount: 消耗金额(消耗业绩总金额) - /// - HeadCount: 人头(按客户去重) - /// - PersonCount: 人次(按客户+日期去重,同一客户不同天算多次) - /// - ProjectCount: 消耗项目数(项目总次数) - /// - RefundAmount: 退卡金额(健康师退卡业绩总金额) - /// - LaborCost: 手工费(消耗时的手工费总金额) - /// - OriginalLaborCost: 原始手工费(消耗时的原始手工费总金额) - /// - OvertimeLaborCost: 加班手工费(消耗时的加班手工费总金额) - /// - /// 查询参数 - /// 健康师统计数据列表 - /// 成功返回统计数据 - /// 参数错误 - /// 服务器错误 - [HttpGet("get-health-coach-statistics_bak")] - public async Task GetHealthCoachStatistics_bak([FromQuery] HealthCoachStatisticsQueryInput input) - { - try - { - // 设置默认时间范围(如果未提供,默认为当月) - var startTime = input.StartTime ?? new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1); - var endTime = input.EndTime ?? DateTime.Now; - - // 构建SQL查询 - var sql = $@" - SELECT - u.F_Id as EmployeeId, - u.F_REALNAME as EmployeeName, - u.F_MDID as StoreId, - md.dm as StoreName, - md.syb as DepartmentId, - dept.F_FullName as DepartmentName, - - -- 邀约人数 - COALESCE(invite_stats.InviteCount, 0) as InviteCount, - - -- 预约人数(无论状态) - COALESCE(appointment_stats.AppointmentCount, 0) as AppointmentCount, - - -- 到店人数(已确认状态) - COALESCE(visit_stats.VisitCount, 0) as VisitCount, - - -- 开单人数和金额 - COALESCE(billing_stats.BillingCount, 0) as BillingCount, - COALESCE(billing_stats.BillingAmount, 0) as BillingAmount, - - -- 消耗相关统计 - COALESCE(consume_stats.ConsumeAmount, 0) as ConsumeAmount, - CAST(COALESCE(headcount_stats.HeadCount, 0) AS DECIMAL(18,2)) as HeadCount, - CAST(COALESCE(personcount_stats.PersonCount, 0) AS DECIMAL(18,2)) as PersonCount, - CAST(COALESCE(invalid_headcount_stats.HeadCount, 0) AS DECIMAL(18,2)) as InvalidHeadCount, - CAST(COALESCE(invalid_personcount_stats.PersonCount, 0) AS DECIMAL(18,2)) as InvalidPersonCount, - CAST(COALESCE(consume_stats.ProjectCount, 0) AS DECIMAL(18,2)) as ProjectCount, - - -- 退卡金额 - COALESCE(refund_stats.RefundAmount, 0) as RefundAmount, - - -- 手工费相关统计 - COALESCE(consume_stats.LaborCost, 0) as LaborCost, - COALESCE(consume_stats.OriginalLaborCost, 0) as OriginalLaborCost, - COALESCE(consume_stats.OvertimeLaborCost, 0) as OvertimeLaborCost - - FROM BASE_USER u - LEFT JOIN lq_mdxx md ON u.F_MDID = md.F_Id - LEFT JOIN base_organize dept ON md.syb = dept.F_Id - - -- 邀约统计子查询 - LEFT JOIN ( - SELECT - yyr as EmployeeId, - COUNT(DISTINCT yykh) as InviteCount - FROM lq_yaoyjl - WHERE yyr IS NOT NULL - AND F_CreateTime >= @startTime - AND F_CreateTime <= @endTime - GROUP BY yyr - ) invite_stats ON u.F_Id = invite_stats.EmployeeId - - -- 预约统计子查询 - LEFT JOIN ( - SELECT - yyr as EmployeeId, - COUNT(DISTINCT gk) as AppointmentCount - FROM lq_yyjl - WHERE yyr IS NOT NULL - AND F_CreateTime >= @startTime - AND F_CreateTime <= @endTime - GROUP BY yyr - ) appointment_stats ON u.F_Id = appointment_stats.EmployeeId - - -- 到店统计子查询 - LEFT JOIN ( - SELECT - yyr as EmployeeId, - COUNT(DISTINCT gk) as VisitCount - FROM lq_yyjl - WHERE yyr IS NOT NULL - AND F_Status = '已确认' - AND F_CreateTime >= @startTime - AND F_CreateTime <= @endTime - GROUP BY yyr - ) visit_stats ON u.F_Id = visit_stats.EmployeeId - - -- 开单统计子查询 - LEFT JOIN ( - SELECT - jkszh as EmployeeId, - COUNT(DISTINCT glkdbh) as BillingCount, - SUM(CAST(jksyj AS DECIMAL(18,2))) as BillingAmount - FROM lq_kd_jksyj - WHERE jkszh IS NOT NULL - AND F_IsEffective = 1 - AND yjsj >= @startTime - AND yjsj <= @endTime - GROUP BY jkszh - ) billing_stats ON u.F_Id = billing_stats.EmployeeId - - -- 消耗统计子查询 - LEFT JOIN ( - SELECT - jksyj.jks as EmployeeId, - SUM(jksyj.jksyj) as ConsumeAmount, - CAST(SUM(jksyj.F_kdpxNumber) AS DECIMAL(18,2)) as ProjectCount, - COALESCE(SUM(jksyj.F_LaborCost), 0) as LaborCost, - COALESCE(SUM(jksyj.F_OriginalLaborCost), 0) as OriginalLaborCost, - COALESCE(SUM(jksyj.F_OvertimeLaborCost), 0) as OvertimeLaborCost - FROM lq_xh_jksyj jksyj - INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id - WHERE jksyj.jks IS NOT NULL - AND jksyj.F_IsEffective = 1 - AND hyhk.F_IsEffective = 1 - AND hyhk.hksj >= @startTime - AND hyhk.hksj <= @endTime - GROUP BY jksyj.jks - ) consume_stats ON u.F_Id = consume_stats.EmployeeId - - -- 有效人头统计子查询(从人次记录表获取,按月份+客户+数量去重后累加数量,F_HasBilling=1) - LEFT JOIN ( - SELECT - F_PersonId as EmployeeId, - CAST(COALESCE(SUM(F_Quantity), 0) AS DECIMAL(18,2)) as HeadCount - FROM ( - SELECT - F_PersonId, - F_WorkMonth, - F_MemberId, - F_Quantity - FROM lq_person_times_record - WHERE F_PersonId IS NOT NULL - AND F_IsEffective = 1 - AND F_PersonType = '健康师' - AND F_HasBilling = 1 - AND F_WorkDate >= DATE(@startTime) - AND F_WorkDate <= DATE(@endTime) - GROUP BY F_PersonId, F_WorkMonth, F_MemberId, F_Quantity - ) as distinct_headcount - GROUP BY F_PersonId - ) headcount_stats ON u.F_Id = headcount_stats.EmployeeId - - -- 有效人次统计子查询(从人次记录表获取,按日期+客户+数量去重后累加数量,F_HasBilling=1) - LEFT JOIN ( - SELECT - F_PersonId as EmployeeId, - CAST(COALESCE(SUM(F_Quantity), 0) AS DECIMAL(18,2)) as PersonCount - FROM ( - SELECT - F_PersonId, - F_WorkDate, - F_MemberId, - F_Quantity - FROM lq_person_times_record - WHERE F_PersonId IS NOT NULL - AND F_IsEffective = 1 - AND F_PersonType = '健康师' - AND F_HasBilling = 1 - AND F_WorkDate >= DATE(@startTime) - AND F_WorkDate <= DATE(@endTime) - GROUP BY F_PersonId, F_WorkDate, F_MemberId, F_Quantity - ) as distinct_personcount - GROUP BY F_PersonId - ) personcount_stats ON u.F_Id = personcount_stats.EmployeeId - - -- 无效人头统计子查询(从人次记录表获取,按月份+客户+数量去重后累加数量,F_HasBilling=0) - LEFT JOIN ( - SELECT - F_PersonId as EmployeeId, - CAST(COALESCE(SUM(F_Quantity), 0) AS DECIMAL(18,2)) as HeadCount - FROM ( - SELECT - F_PersonId, - F_WorkMonth, - F_MemberId, - F_Quantity - FROM lq_person_times_record - WHERE F_PersonId IS NOT NULL - AND F_IsEffective = 1 - AND F_PersonType = '健康师' - AND F_HasBilling = 0 - AND F_WorkDate >= DATE(@startTime) - AND F_WorkDate <= DATE(@endTime) - GROUP BY F_PersonId, F_WorkMonth, F_MemberId, F_Quantity - ) as distinct_headcount - GROUP BY F_PersonId - ) invalid_headcount_stats ON u.F_Id = invalid_headcount_stats.EmployeeId - - -- 无效人次统计子查询(从人次记录表获取,按日期+客户+数量去重后累加数量,F_HasBilling=0) - LEFT JOIN ( - SELECT - F_PersonId as EmployeeId, - CAST(COALESCE(SUM(F_Quantity), 0) AS DECIMAL(18,2)) as PersonCount - FROM ( - SELECT - F_PersonId, - F_WorkDate, - F_MemberId, - F_Quantity - FROM lq_person_times_record - WHERE F_PersonId IS NOT NULL - AND F_IsEffective = 1 - AND F_PersonType = '健康师' - AND F_HasBilling = 0 - AND F_WorkDate >= DATE(@startTime) - AND F_WorkDate <= DATE(@endTime) - GROUP BY F_PersonId, F_WorkDate, F_MemberId, F_Quantity - ) as distinct_personcount - GROUP BY F_PersonId - ) invalid_personcount_stats ON u.F_Id = invalid_personcount_stats.EmployeeId - - -- 退卡统计子查询 - LEFT JOIN ( - SELECT - jkszh as EmployeeId, - SUM(CAST(jksyj AS DECIMAL(18,2))) as RefundAmount - FROM lq_hytk_jksyj - WHERE jkszh IS NOT NULL - AND F_IsEffective = 1 - AND tksj >= @startTime - AND tksj <= @endTime - GROUP BY jkszh - ) refund_stats ON u.F_Id = refund_stats.EmployeeId - - WHERE u.F_GW = '健康师' - "; - - // 添加条件过滤 - var conditions = new List(); - var parameters = new List - { - new SugarParameter("@startTime", startTime), - new SugarParameter("@endTime", endTime) - }; - - if (!string.IsNullOrEmpty(input.DepartmentId)) - { - conditions.Add("md.syb = @departmentId"); - parameters.Add(new SugarParameter("@departmentId", input.DepartmentId)); - } - - if (!string.IsNullOrEmpty(input.StoreId)) - { - conditions.Add("u.F_MDID = @storeId"); - parameters.Add(new SugarParameter("@storeId", input.StoreId)); - } - - if (!string.IsNullOrEmpty(input.EmployeeName)) - { - conditions.Add("u.F_REALNAME LIKE @employeeName"); - parameters.Add(new SugarParameter("@employeeName", $"%{input.EmployeeName}%")); - } - - if (conditions.Any()) - { - sql += " AND " + string.Join(" AND ", conditions); - } - - sql += " ORDER BY u.F_REALNAME"; - - // 执行查询 - var allData = await _db.Ado.SqlQueryAsync(sql, parameters); - - // 手动分页 - var totalCount = allData.Count; - var pagedData = allData - .Skip((input.currentPage - 1) * input.pageSize) - .Take(input.pageSize) - .ToList(); - - // 直接返回分页结果 - return new - { - list = pagedData, - pagination = new - { - pageIndex = input.currentPage, - pageSize = input.pageSize, - totalCount = totalCount - } - }; - } - catch (Exception ex) - { - _logger.LogError(ex, "获取健康师统计数据失败"); - throw NCCException.Oh($"获取健康师统计数据失败:{ex.Message}"); - } - } - #endregion - #region 获取开单品项明细记录列表 /// /// 获取开单品项明细记录列表(分页) @@ -4274,7 +3749,11 @@ namespace NCC.Extend.LqKdKdjlb var sidx = string.IsNullOrEmpty(input.sidx) ? "CreateTime" : input.sidx; // 构建基础查询:储扣信息 JOIN 开单记录 JOIN 客户信息 JOIN 门店信息 - var baseQuery = _db.Queryable((deduct, billing, member, store) => deduct.BillingId == billing.Id && billing.Kdhy == member.Id && billing.Djmd == store.Id) + var baseQuery = _db.Queryable( + (deduct, billing, member, store) => + deduct.BillingId == billing.Id && + billing.Kdhy == member.Id && + billing.Djmd == store.Id) .WhereIF(!string.IsNullOrEmpty(input.DeductType), (deduct, billing, member, store) => deduct.DeductType == input.DeductType) .WhereIF(!string.IsNullOrEmpty(input.DeductId), (deduct, billing, member, store) => deduct.DeductId == input.DeductId) .WhereIF(!string.IsNullOrEmpty(input.BillingId), (deduct, billing, member, store) => deduct.BillingId == input.BillingId) @@ -4294,7 +3773,7 @@ namespace NCC.Extend.LqKdKdjlb (billing.Id != null && billing.Id.Contains(input.keyword))); - // 查询并分页 + // 查询并分页,使用子查询获取开单类型 var data = await baseQuery.Select((deduct, billing, member, store) => new LqKdDeductinfoListOutput { Id = deduct.Id ?? "", @@ -4314,7 +3793,12 @@ namespace NCC.Extend.LqKdKdjlb MemberName = member.Khmc ?? "", MemberPhone = member.Sjh ?? "", StoreId = billing.Djmd ?? "", - StoreName = store.Dm ?? "" + StoreName = store.Dm ?? "", + TimePeriod = billing.Kdrq, + BillingType = SqlFunc.Subqueryable() + .Where(pxmx => pxmx.Id == deduct.DeductId && pxmx.Px == deduct.ItemId) + .Select(pxmx => pxmx.SourceType), + CooperationInstitution = billing.Hgjg ?? "" }).MergeTable().OrderBy(sidx + " " + input.sort).ToPagedListAsync(input.currentPage, input.pageSize); return PageResult.SqlSugarPageResult(data); diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs index bf7d37a..1cc8788 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs @@ -2133,7 +2133,7 @@ namespace NCC.Extend.LqStatistics ) personcount_stats ON jksyj.jkszh = personcount_stats.jkszh AND hyhk.md = personcount_stats.md WHERE jksyj.F_IsEffective = 1 AND DATE_FORMAT(hyhk.hksj, '%Y%m') = @statisticsMonth - GROUP BY jksyj.jkszh, jksyj.jksxm, hyhk.md, md.mdbm, md.dm, headcount_stats.F_HeadCount, personcount_stats.F_PersonCount"; + GROUP BY jksyj.jks, jksyj.jksxm, hyhk.md, md.mdbm, md.dm, headcount_stats.F_HeadCount, personcount_stats.F_PersonCount"; var healthCoachData = await _db.Ado.SqlQueryAsync(healthCoachSql, new { statisticsMonth }); foreach (var item in healthCoachData) diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs index 16ff34f..ea67cc0 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs @@ -777,48 +777,48 @@ namespace NCC.Extend.LqXhHyhk .OrderBy($"{sidx} {sort}") .ToPagedListAsync(input.currentPage, input.pageSize); - // 获取当前页的耗卡记录ID列表 - var consumeIds = data.list.Select(x => x.id).ToList(); + // 获取当前页的耗卡记录ID列表 + var consumeIds = data.list.Select(x => x.id).ToList(); - // 批量查询耗卡明细 - var consumeDetails = new List(); - if (consumeIds.Any()) - { - consumeDetails = await _db.Queryable() - .Where(x => consumeIds.Contains(x.ConsumeInfoId) && x.IsEffective == StatusEnum.有效.GetHashCode()) - .Select(x => new LqXhPxmxInfoOutput - { - id = x.Id, - consumeInfoId = x.ConsumeInfoId, - billingItemId = x.BillingItemId, - px = x.Px, - pxmc = x.Pxmc, - pxjg = x.Pxjg, - memberId = x.MemberId, - createTime = x.CreateTIme, - projectNumber = x.ProjectNumber, - originalProjectNumber = x.OriginalProjectNumber, - overtimeProjectNumber = x.OvertimeProjectNumber, - sourceType = x.SourceType, - totalPrice = x.TotalPrice, - isEffective = x.IsEffective, - }) - .ToListAsync(); - } + // 批量查询耗卡明细 + var consumeDetails = new List(); + if (consumeIds.Any()) + { + consumeDetails = await _db.Queryable() + .Where(x => consumeIds.Contains(x.ConsumeInfoId) && x.IsEffective == StatusEnum.有效.GetHashCode()) + .Select(x => new LqXhPxmxInfoOutput + { + id = x.Id, + consumeInfoId = x.ConsumeInfoId, + billingItemId = x.BillingItemId, + px = x.Px, + pxmc = x.Pxmc, + pxjg = x.Pxjg, + memberId = x.MemberId, + createTime = x.CreateTIme, + projectNumber = x.ProjectNumber, + originalProjectNumber = x.OriginalProjectNumber, + overtimeProjectNumber = x.OvertimeProjectNumber, + sourceType = x.SourceType, + totalPrice = x.TotalPrice, + isEffective = x.IsEffective, + }) + .ToListAsync(); + } - // 按耗卡记录ID分组耗卡明细 - var consumeDetailsGrouped = consumeDetails.GroupBy(x => x.consumeInfoId) - .ToDictionary(g => g.Key, g => g.ToList()); + // 按耗卡记录ID分组耗卡明细 + var consumeDetailsGrouped = consumeDetails.GroupBy(x => x.consumeInfoId) + .ToDictionary(g => g.Key, g => g.ToList()); - // 为每个耗卡记录分配耗卡明细 - foreach (var item in data.list) - { - item.ConsumeDetails = consumeDetailsGrouped.ContainsKey(item.id) - ? consumeDetailsGrouped[item.id] - : new List(); - } + // 为每个耗卡记录分配耗卡明细 + foreach (var item in data.list) + { + item.ConsumeDetails = consumeDetailsGrouped.ContainsKey(item.id) + ? consumeDetailsGrouped[item.id] + : new List(); + } - return PageResult.SqlSugarPageResult(data); + return PageResult.SqlSugarPageResult(data); } catch (Exception ex) { @@ -1390,6 +1390,8 @@ namespace NCC.Extend.LqXhHyhk } } } + //查询开单记录 + var billingRecord = await _db.Queryable().Where(x => x.Kdhy == entity.Hy && x.IsEffective == StatusEnum.有效.GetHashCode() && x.Sfyj > 0).AnyAsync(); //剔除所有T区健康师(姓名中包含"T区"的健康师) var NoTallJksyjEntities = allJksyjEntities.Where(x => x.Jks != null && x.Jks != "" && (x.Jksxm == null || !x.Jksxm.Contains("T区"))).ToList(); //获取这次耗卡有多少个健康师 @@ -1412,6 +1414,7 @@ namespace NCC.Extend.LqXhHyhk Quantity = 1 / (decimal)jksCount, CreateTime = DateTime.Now, IsEffective = StatusEnum.有效.GetHashCode(), + HasBilling = billingRecord ? 1 : 0, }; allPersonTimesRecordEntities.Add(personTimesRecordEntity); } @@ -1437,6 +1440,7 @@ namespace NCC.Extend.LqXhHyhk Quantity = 1 / (decimal)kjbCount, CreateTime = DateTime.Now, IsEffective = StatusEnum.有效.GetHashCode(), + HasBilling = billingRecord ? 1 : 0, }; allPersonTimesRecordEntities.Add(personTimesRecordEntity); } diff --git a/sql/修复人次记录HasBilling字段.sql b/sql/修复人次记录HasBilling字段.sql new file mode 100644 index 0000000..f779051 --- /dev/null +++ b/sql/修复人次记录HasBilling字段.sql @@ -0,0 +1,47 @@ +-- 修复人次记录表中F_HasBilling字段 +-- 对于耗卡类型的人次记录,如果会员有开单记录(F_IsEffective=1且Sfyj>0),则设置F_HasBilling=1 + +-- 1. 先查看需要修复的记录数量 +SELECT COUNT(*) as need_fix_count +FROM lq_person_times_record ptr +WHERE ptr.F_BusinessType = '耗卡' + AND ptr.F_HasBilling = 0 + AND ptr.F_MemberId IS NOT NULL + AND ptr.F_MemberId != '' + AND EXISTS ( + SELECT 1 + FROM lq_kd_kdjlb kd + WHERE kd.Kdhy = ptr.F_MemberId + AND kd.F_IsEffective = 1 + AND kd.Sfyj > 0 + ); + +-- 2. 修复耗卡类型的人次记录 +UPDATE lq_person_times_record ptr +INNER JOIN ( + SELECT DISTINCT Kdhy + FROM lq_kd_kdjlb + WHERE F_IsEffective = 1 + AND Sfyj > 0 +) kd ON ptr.F_MemberId = kd.Kdhy +SET ptr.F_HasBilling = 1 +WHERE ptr.F_BusinessType = '耗卡' + AND ptr.F_HasBilling = 0 + AND ptr.F_MemberId IS NOT NULL + AND ptr.F_MemberId != ''; + +-- 3. 验证修复结果(可选) +SELECT COUNT(*) as fixed_count +FROM lq_person_times_record ptr +WHERE ptr.F_BusinessType = '耗卡' + AND ptr.F_HasBilling = 1 + AND ptr.F_MemberId IS NOT NULL + AND ptr.F_MemberId != '' + AND EXISTS ( + SELECT 1 + FROM lq_kd_kdjlb kd + WHERE kd.Kdhy = ptr.F_MemberId + AND kd.F_IsEffective = 1 + AND kd.Sfyj > 0 + ); + diff --git a/项目信息-薪酬规则与名词解释.md b/项目信息-薪酬规则与名词解释.md index 8c2a33c..c0b12e1 100644 --- a/项目信息-薪酬规则与名词解释.md +++ b/项目信息-薪酬规则与名词解释.md @@ -124,8 +124,8 @@ ### 顾问提成规则 -- **高级顾问**:战队总业绩 ≥ 6万元 且 组员业绩达到40%以上 且 消耗达到6万元 → 团队总业绩0.8% -- **普通顾问**:战队总业绩 ≥ 4万元 且 组员业绩达到30%以上 且 消耗达到4万元 → 团队总业绩0.3% +- 战队总业绩 ≥ 6万元 且 组员业绩达到40%以上 且 消耗达到6万元 → 团队总业绩0.8% +- 战队总业绩 ≥ 4万元 且 组员业绩达到30%以上 且 消耗达到4万元 → 团队总业绩0.3% ### 店助考核规则 -- libgit2 0.21.4