事业部开单统计播报问题分析.md 10.3 KB

事业部开单统计播报问题分析

问题描述:绿纤西站店没有在事业部开单统计数据播报中显示
分析日期:2025年1月
问题类型:数据统计逻辑错误


一、问题定位

1.1 播报流程

触发时机:在创建开单记录时(LqKdKdjlbService.Create 方法)

流程

  1. 开单创建成功后,判断 sfyj > 0kdrq 有值
  2. 调用 LqDailyReportService.GetBusinessUnitBillingStatisticsText 获取统计数据文本
  3. 如果文本不为空且不包含"暂无开单数据",则发送到企业微信群

代码位置LqKdKdjlbService.cs 第1506-1536行


1.2 统计数据获取逻辑

方法LqDailyReportService.GetBusinessUnitBillingStatistics
位置LqDailyReportService.cs 第1513-1604行

当前实现(❌ 错误):

// 2. 查询指定日期的有效开单记录(有金额的)
var billingQuery = _db.Queryable<LqKdKdjlbEntity, LqMdxxEntity, OrganizeEntity>(
        (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 中的归属字段(sybjybkjbdxmbgsqssjgszzsjstatus)视为历史字段,禁止再作为业务统计或归属判断的依据

2.2 正确的实现方式

在同一个文件的 GetBusinessUnitPerformanceCompletion 方法中(第418-433行),使用了正确的实现方式:

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_kdjlblq_md_target(通过门店ID和月份)
    • lq_md_targetbase_organize(通过事业部ID)

4.2 修复后的查询逻辑

方案一:使用 SqlSugar 查询(推荐)

// 1. 根据开单日期确定月份(YYYYMM格式)
var month = targetDate.ToString("yyyyMM");

// 2. 查询指定日期的有效开单记录(有金额的)
var billingQuery = _db.Queryable<LqKdKdjlbEntity, LqMdTargetEntity, OrganizeEntity>(
        (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查询(更灵活)

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` 表中的月份归属正确统计
- ✅ 出现在对应事业部的播报内容中
- ✅ 符合项目规范要求

---

**文档结束**