# 事业部开单统计播报问题分析 **问题描述**:绿纤西站店没有在事业部开单统计数据播报中显示 **分析日期**:2025年1月 **问题类型**:数据统计逻辑错误 --- ## 一、问题定位 ### 1.1 播报流程 **触发时机**:在创建开单记录时(`LqKdKdjlbService.Create` 方法) **流程**: 1. 开单创建成功后,判断 `sfyj > 0` 且 `kdrq` 有值 2. 调用 `LqDailyReportService.GetBusinessUnitBillingStatisticsText` 获取统计数据文本 3. 如果文本不为空且不包含"暂无开单数据",则发送到企业微信群 **代码位置**:`LqKdKdjlbService.cs` 第1506-1536行 --- ### 1.2 统计数据获取逻辑 **方法**:`LqDailyReportService.GetBusinessUnitBillingStatistics` **位置**:`LqDailyReportService.cs` 第1513-1604行 **当前实现**(❌ **错误**): ```csharp // 2. 查询指定日期的有效开单记录(有金额的) var billingQuery = _db.Queryable( (billing, store, org) => billing.Djmd == store.Id && store.Syb == org.Id) .Where((billing, store, org) => billing.IsEffective == StatusEnum.有效.GetHashCode()) .Where((billing, store, org) => billing.Sfyj > 0) .Where((billing, store, org) => billing.Kdrq.HasValue && billing.Kdrq.Value.Date == targetDate.Date) .Where((billing, store, org) => org.Category == "department") .Where((billing, store, org) => org.FullName.Contains("事业")) ``` **问题**: - ❌ 使用 `store.Syb == org.Id` 直接从 `lq_mdxx` 表的 `syb` 字段读取事业部归属 - ❌ 没有考虑月份维度,门店归属可能在不同月份发生变化 - ❌ 违反了项目规范:**门店归属一律从 `lq_md_target` 按月份维度管理** --- ## 二、问题根因分析 ### 2.1 项目规范要求 根据项目规范(`.cursor/rules/project_rules.mdc`): > **lq_mdxx_mdgs (门店归属表) 已弃用**: 门店归属信息不再从 `lq_mdxx` 直接读取 > - **门店归属一律从 `lq_md_target` 按月份维度管理**:通过 `F_StoreId + F_Month` 获取对应月份的事业部/经营部/科技部/旗舰店等归属信息 > - `lq_mdxx` 中的归属字段(`syb`、`jyb`、`kjb`、`dxmb`、`gsqssj`、`gszzsj`、`status`)视为历史字段,**禁止再作为业务统计或归属判断的依据** ### 2.2 正确的实现方式 在同一个文件的 `GetBusinessUnitPerformanceCompletion` 方法中(第418-433行),使用了正确的实现方式: ```sql SELECT target.F_BusinessUnit as BusinessUnitId, COALESCE(SUM(billing.sfyj), 0) as BillingPerformance FROM lq_kd_kdjlb billing INNER JOIN lq_md_target target ON billing.djmd = target.F_StoreId AND target.F_Month = '{month}' INNER JOIN base_organize o ON target.F_BusinessUnit = o.F_Id WHERE billing.F_IsEffective = 1 AND target.F_BusinessUnit IS NOT NULL AND o.F_Category = 'department' AND (o.F_DeleteMark IS NULL OR o.F_DeleteMark != 1) AND o.F_FullName IN ('事业一部', '事业二部', '事业三部', '事业四部', '事业五部', '事业六部') AND DATE(billing.kdrq) >= '{startDate:yyyy-MM-dd}' AND DATE(billing.kdrq) <= '{endDate:yyyy-MM-dd}' AND target.F_BusinessUnit IN ('{unitIdsStr}') GROUP BY target.F_BusinessUnit ``` **关键点**: - ✅ 使用 `lq_md_target` 表获取门店归属 - ✅ 通过 `target.F_Month = '{month}'` 按月份维度筛选 - ✅ 通过 `target.F_BusinessUnit` 获取事业部ID --- ### 2.3 为什么绿纤西站店没有被统计 **可能的原因**: 1. **`lq_mdxx.syb` 字段为空或错误** - 如果绿纤西站店在 `lq_mdxx` 表的 `syb` 字段中没有正确设置 - 或者 `syb` 字段指向的组织不是"事业X部"(不包含"事业"关键字) - 则不会被统计进去 2. **`lq_md_target` 表中有正确的归属,但查询没有使用** - 如果绿纤西站店在 `lq_md_target` 表中有正确的月份归属记录 - 但查询使用的是 `lq_mdxx.syb`,导致数据不一致 3. **月份维度问题** - 如果查询时使用的月份与 `lq_md_target` 表中的月份不匹配 - 或者该门店在查询月份没有 `lq_md_target` 记录 --- ## 三、问题影响 ### 3.1 数据准确性 - ❌ 统计数据不准确,可能遗漏部分门店的开单数据 - ❌ 播报内容不完整,影响决策 ### 3.2 业务影响 - ❌ 绿纤西站店的开单数据没有被播报 - ❌ 可能导致事业部业绩统计不准确 - ❌ 影响数据分析和决策 --- ## 四、修复方案 ### 4.1 修复思路 **核心原则**:按照项目规范,门店归属必须从 `lq_md_target` 表按月份维度获取 **修复步骤**: 1. **修改查询逻辑**: - 不再使用 `lq_mdxx.syb` 字段 - 改为使用 `lq_md_target` 表,通过 `F_StoreId + F_Month` 获取门店归属 2. **确定月份**: - 根据开单日期(`kdrq`)确定月份(YYYYMM格式) - 使用该月份在 `lq_md_target` 表中查找门店归属 3. **关联查询**: - `lq_kd_kdjlb` ← `lq_md_target`(通过门店ID和月份) - `lq_md_target` ← `base_organize`(通过事业部ID) --- ### 4.2 修复后的查询逻辑 **方案一:使用 SqlSugar 查询(推荐)** ```csharp // 1. 根据开单日期确定月份(YYYYMM格式) var month = targetDate.ToString("yyyyMM"); // 2. 查询指定日期的有效开单记录(有金额的) var billingQuery = _db.Queryable( (billing, target, org) => billing.Djmd == target.StoreId && target.Month == month && target.BusinessUnit == org.Id) .Where((billing, target, org) => billing.IsEffective == StatusEnum.有效.GetHashCode()) .Where((billing, target, org) => billing.Sfyj > 0) .Where((billing, target, org) => billing.Kdrq.HasValue && billing.Kdrq.Value.Date == targetDate.Date) .Where((billing, target, org) => target.BusinessUnit != null && target.BusinessUnit != "") .Where((billing, target, org) => org.Category == "department") .Where((billing, target, org) => org.FullName.Contains("事业")) .Select((billing, target, org) => new { OrderId = billing.Id, StoreName = billing.Djmd, // 需要关联门店表获取门店名称 BusinessUnitId = org.Id, BusinessUnitName = org.FullName, Amount = billing.Sfyj, OrderTime = billing.Kdrq, }) .ToListAsync(); ``` **方案二:使用原生SQL查询(更灵活)** ```sql SELECT billing.F_Id as OrderId, store.dm as StoreName, org.F_Id as BusinessUnitId, org.F_FullName as BusinessUnitName, billing.sfyj as Amount, billing.kdrq as OrderTime FROM lq_kd_kdjlb billing INNER JOIN lq_md_target target ON billing.djmd = target.F_StoreId AND target.F_Month = '{month}' INNER JOIN lq_mdxx store ON billing.djmd = store.F_Id INNER JOIN base_organize org ON target.F_BusinessUnit = org.F_Id WHERE billing.F_IsEffective = 1 AND billing.sfyj > 0 AND DATE(billing.kdrq) = '{targetDate:yyyy-MM-dd}' AND target.F_BusinessUnit IS NOT NULL AND org.F_Category = 'department' AND (org.F_DeleteMark IS NULL OR org.F_DeleteMark != 1) AND org.F_FullName IN ('事业一部', '事业二部', '事业三部', '事业四部', '事业五部', '事业六部') ``` --- ### 4.3 需要修改的代码 **文件**:`netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs` **方法**:`GetBusinessUnitBillingStatistics`(第1513-1604行) **修改内容**: 1. 添加月份计算逻辑(根据 `targetDate` 计算月份) 2. 修改查询逻辑,使用 `lq_md_target` 表替代 `lq_mdxx.syb` 3. 添加门店名称的关联查询(如果需要) --- ## 五、验证方案 ### 5.1 验证步骤 1. **检查绿纤西站店的数据**: ```sql -- 检查门店基础信息 SELECT F_Id, dm, syb FROM lq_mdxx WHERE dm LIKE '%西站%'; -- 检查门店目标表中的归属信息 SELECT F_StoreId, F_Month, F_BusinessUnit FROM lq_md_target WHERE F_StoreId = (SELECT F_Id FROM lq_mdxx WHERE dm LIKE '%西站%' LIMIT 1) ORDER BY F_Month DESC; -- 检查该门店的开单记录 SELECT F_Id, djmd, kdrq, sfyj, F_IsEffective FROM lq_kd_kdjlb WHERE djmd = (SELECT F_Id FROM lq_mdxx WHERE dm LIKE '%西站%' LIMIT 1) AND DATE(kdrq) = '2025-01-23' -- 替换为实际日期 AND sfyj > 0 AND F_IsEffective = 1; ``` 2. **对比修复前后的数据**: - 修复前:使用 `lq_mdxx.syb` 查询 - 修复后:使用 `lq_md_target` 查询 - 验证绿纤西站店是否出现在统计结果中 3. **测试播报功能**: - 创建一个绿纤西站店的开单记录 - 验证播报内容中是否包含该门店 --- ### 5.2 预期结果 修复后: - ✅ 绿纤西站店的开单数据应该出现在统计结果中 - ✅ 播报内容应该包含该门店的开单信息 - ✅ 统计数据应该与 `lq_md_target` 表中的归属信息一致 --- ## 六、风险评估 ### 6.1 数据一致性风险 - ⚠️ 如果某些门店在 `lq_md_target` 表中没有对应月份的记录,可能不会被统计 - **建议**:添加容错处理,如果 `lq_md_target` 中没有记录,可以回退到 `lq_mdxx.syb`(但需要记录日志) ### 6.2 性能风险 - ⚠️ 使用 `lq_md_target` 表关联查询可能比直接使用 `lq_mdxx.syb` 稍慢 - **建议**:确保 `lq_md_target` 表有适当的索引(`F_StoreId + F_Month` 唯一索引已存在) --- ## 七、修复优先级 **优先级**:🔴 **高** **原因**: 1. 影响数据准确性 2. 违反项目规范 3. 导致业务数据不完整 --- ## 八、总结 ### 8.1 问题根源 **核心问题**:`GetBusinessUnitBillingStatistics` 方法使用了错误的门店归属获取方式 - ❌ 当前实现:从 `lq_mdxx.syb` 字段读取(已弃用的历史字段) - ✅ 应该使用:从 `lq_md_target` 表按月份维度获取 ### 8.2 修复方向 1. **修改查询逻辑**:使用 `lq_md_target` 表替代 `lq_mdxx.syb` 2. **添加月份维度**:根据开单日期确定月份,使用该月份的门店归属 3. **保持一致性**:与其他统计方法(如 `GetBusinessUnitPerformanceCompletion`)保持一致 ### 8.3 预期效果 修复后,绿纤西站店(以及其他所有门店)的开单数据将: - ✅ 根据 `lq_md_target` 表中的月份归属正确统计 - ✅ 出现在对应事业部的播报内容中 - ✅ 符合项目规范要求 --- **文档结束**