Commit 0cfc43b972d5e4d68d850590571dd105c05ba4fb

Authored by “wangming”
1 parent 087f6aff

修复科技部总经理工资计算逻辑及相关服务优化

- 修复科技部总经理Cell金额计算问题
- 更新主任工资相关服务和前端页面
- 优化科技部老师工资计算逻辑
- 更新客户信息服务和报销申请服务
- 修复系统映射器和权限模型
- 完善工资管理前端页面显示
docs/test-reports/科技部总经理Cell金额计算修复验证.md 0 → 100644
  1 +# 科技部总经理Cell金额计算修复验证报告
  2 +
  3 +## 修复内容
  4 +
  5 +### 1. 改为批量查询(与科技部驾驶舱接口保持一致)
  6 +
  7 +**修复前**:逐个门店循环查询
  8 +```csharp
  9 +foreach (var storeId in allManagedStoreIds)
  10 +{
  11 + // 单个门店查询
  12 + var storeCellBillingSql = $"SELECT ... WHERE F_StoreId = '{storeId}' ...";
  13 +}
  14 +```
  15 +
  16 +**修复后**:批量查询所有门店,然后按门店分组
  17 +```csharp
  18 +// 批量查询所有门店的开单Cell金额
  19 +var allStoreCellBillingSql = $@"
  20 + SELECT F_StoreId, COALESCE(SUM(CAST(jksyj AS DECIMAL(18,2))), 0) as Amount
  21 + FROM lq_kd_jksyj
  22 + WHERE F_IsEffective = 1
  23 + AND F_StoreId IN ('{string.Join("','", allManagedStoreIds)}')
  24 + AND (F_BeautyType = 'cell' OR F_BeautyType = 'Cell')
  25 + AND yjsj >= '{startDateStr}'
  26 + AND yjsj <= '{endDateTimeStr}'
  27 + GROUP BY F_StoreId";
  28 +```
  29 +
  30 +### 2. 查询逻辑完全对齐
  31 +
  32 +- ✅ 使用相同的SQL格式
  33 +- ✅ 使用相同的时间范围处理
  34 +- ✅ 使用相同的CAST转换
  35 +- ✅ 使用相同的退卡金额查询逻辑
  36 +
  37 +## 预期结果
  38 +
  39 +- **Cell金额合计**:**69,838.00** 元
  40 +- **关键门店**:
  41 + - 绿纤静居寺店:46,110.00 元
  42 + - 绿纤468店:0.00 元
  43 + - 绿纤明信店:2,200.00 元
  44 +
  45 +## 验证步骤
  46 +
  47 +1. **重启服务**(必须)
  48 +2. **调用计算接口**
  49 +3. **验证数据库结果**
... ...
docs/test-reports/科技部总经理Cell金额计算测试报告.md 0 → 100644
  1 +# 科技部总经理Cell金额计算测试报告
  2 +
  3 +## 测试目的
  4 +验证科技部总经理工资计算接口的Cell金额计算是否正确,是否与科技部驾驶舱接口的计算结果一致。
  5 +
  6 +## 测试时间
  7 +2026-01-14
  8 +
  9 +## 测试步骤
  10 +
  11 +### 1. 调用计算接口
  12 +```bash
  13 +POST /api/Extend/lqtechgeneralmanagersalary/calculate/tech-general-manager?year=2025&month=12
  14 +```
  15 +
  16 +**响应**:
  17 +```json
  18 +{
  19 + "code": 200,
  20 + "msg": "操作成功",
  21 + "data": null
  22 +}
  23 +```
  24 +
  25 +### 2. 查询计算结果
  26 +
  27 +**夏萍的工资记录**:
  28 +```sql
  29 +SELECT F_EmployeeName, F_StatisticsMonth, F_CellAmount, F_TraceabilityAmount, F_CellCommissionAmount
  30 +FROM lq_tech_general_manager_salary_statistics
  31 +WHERE F_EmployeeName LIKE '%夏萍%' AND F_StatisticsMonth = '202512'
  32 +```
  33 +
  34 +**结果**:
  35 +- Cell金额:**60,994.30** 元
  36 +- 溯源金额:347,256.00 元
  37 +- Cell提成金额:109.94 元
  38 +- 记录状态:未锁定(IsLocked = 0),未确认(EmployeeConfirmStatus = 0)
  39 +
  40 +### 3. 对比科技部驾驶舱接口
  41 +
  42 +**科技部驾驶舱接口**:
  43 +```bash
  44 +POST /api/Extend/LqTechDepartmentDashboard/GetStatistics
  45 +{
  46 + "statisticsMonth": "202512",
  47 + "techDepartmentId": "734725579919590661",
  48 + "storeIds": []
  49 +}
  50 +```
  51 +
  52 +**结果**:
  53 +- Cell金额:**69,838.00** 元
  54 +- 开单Cell金额:69,838.00 元
  55 +- 退卡Cell金额:0.00 元
  56 +- 溯源金额:356,848.50 元
  57 +
  58 +### 4. 差异分析
  59 +
  60 +| 指标 | 工资计算接口 | 科技部驾驶舱接口 | 差异 |
  61 +|------|------------|----------------|------|
  62 +| Cell金额 | 60,994.30 | 69,838.00 | **-8,843.70** |
  63 +
  64 +**门店明细差异**(从门店明细JSON中提取):
  65 +- 绿纤静居寺店:37,400.00 → 预期:46,110.00(+8,710.00)
  66 +- 绿纤468店:66.30 → 预期:0.00(-66.30)
  67 +- 绿纤明信店:2,000.00 → 预期:2,200.00(+200.00)
  68 +
  69 +## 代码修改情况
  70 +
  71 +### 已完成的修改
  72 +1. ✅ 添加 `endDateTime` 变量,使用与科技部驾驶舱接口相同的时间范围处理方式
  73 +2. ✅ 修改开单溯源金额和开单Cell金额的查询方式,从 SqlSugar ORM 改为原生SQL
  74 +3. ✅ 修改退卡金额的时间范围,从 `endDate.AddDays(1)` 改为 `endDate.Date`
  75 +4. ✅ 更新接口注释,说明修改内容
  76 +
  77 +### 代码位置
  78 +- 文件:`netcore/src/Modularity/Extend/NCC.Extend/LqTechGeneralManagerSalaryService.cs`
  79 +- 方法:`CalculateTechGeneralManagerSalary`
  80 +- 修改行:232-372
  81 +
  82 +## 问题分析
  83 +
  84 +### 数据未更新的原因
  85 +数据仍然显示为旧值(60,994.30),可能的原因:
  86 +1. **服务未重启**:代码已修改并编译通过,但服务可能还未重启,仍在使用旧代码
  87 +2. **代码未生效**:虽然接口返回成功,但可能由于缓存或其他原因,新代码未执行
  88 +
  89 +### 验证代码是否正确
  90 +代码逻辑检查:
  91 +- ✅ `endDateTime` 变量已正确定义(第232行)
  92 +- ✅ 开单Cell金额SQL查询使用 `endDateTime`(第360行)
  93 +- ✅ 退卡Cell金额使用 `endDate.Date` 范围(第371行)
  94 +
  95 +## 建议
  96 +
  97 +### 1. 重启服务
  98 +**必须重启服务**以使新代码生效:
  99 +- 如果使用 `dotnet watch run`,可能需要手动重启
  100 +- 如果使用服务部署,需要重新部署或重启服务
  101 +
  102 +### 2. 重新执行计算
  103 +服务重启后,重新调用计算接口:
  104 +```bash
  105 +POST /api/Extend/lqtechgeneralmanagersalary/calculate/tech-general-manager?year=2025&month=12
  106 +```
  107 +
  108 +### 3. 验证结果
  109 +重新计算后,验证:
  110 +- Cell金额应该为 **69,838.00** 元(与科技部驾驶舱接口一致)
  111 +- 门店明细中的Cell金额应该更新为正确值
  112 +
  113 +## 预期结果
  114 +
  115 +修改后的代码应该能够计算出:
  116 +- **Cell金额**:69,838.00 元(与科技部驾驶舱接口一致)
  117 +- **门店明细**:
  118 + - 绿纤静居寺店:46,110.00 元
  119 + - 绿纤468店:0.00 元
  120 + - 绿纤明信店:2,200.00 元
  121 +
  122 +## 测试结论
  123 +
  124 +- ✅ 代码修改完成,编译通过
  125 +- ⚠️ 服务需要重启才能使新代码生效
  126 +- ⏳ 待服务重启后重新测试验证
... ...
docs/test-reports/科技部总经理Cell金额计算问题修复总结.md 0 → 100644
  1 +# 科技部总经理Cell金额计算问题修复总结
  2 +
  3 +## 问题描述
  4 +科技部总经理工资计算接口中,Cell金额计算不正确。预期值:**69,838.00** 元,实际值:**60,994.30** 元。
  5 +
  6 +## 问题分析
  7 +
  8 +### 1. SQL查询验证
  9 +直接SQL查询结果正确:
  10 +- 绿纤静居寺店 (1649328471923847173): **46,110.00** 元(数据库中:37,400.00)
  11 +- 绿纤468店 (1649328471923847175): **0.00** 元(数据库中:66.30)
  12 +- 绿纤明信店 (1649328471923847187): **2,200.00** 元(数据库中:2,000.00)
  13 +
  14 +### 2. 根本原因
  15 +1. **时间格式化问题**:代码中使用字符串插值格式化DateTime时可能有问题
  16 +2. **更新机制问题**:SqlSugar的Updateable可能只更新有变化的字段
  17 +
  18 +## 已修复的问题
  19 +
  20 +### 1. 时间格式化修复
  21 +- 将字符串插值中的时间格式化改为使用 `.ToString()` 方法
  22 +- 在循环外部定义时间格式化字符串,避免重复计算
  23 +
  24 +```csharp
  25 +// 修复前:
  26 +AND yjsj <= '{endDateTime:yyyy-MM-dd HH:mm:ss}'
  27 +
  28 +// 修复后:
  29 +var startDateStr = startDate.ToString("yyyy-MM-dd HH:mm:ss");
  30 +var endDateTimeStr = endDateTime.ToString("yyyy-MM-dd HH:mm:ss");
  31 +AND yjsj <= '{endDateTimeStr}'
  32 +```
  33 +
  34 +### 2. 强制更新机制
  35 +- 添加 `IgnoreColumns` 确保强制更新所有字段(除了CreateTime和CreateUser)
  36 +
  37 +```csharp
  38 +await _db.Updateable(recordsToUpdate)
  39 + .IgnoreColumns(x => x.CreateTime)
  40 + .IgnoreColumns(x => x.CreateUser)
  41 + .ExecuteCommandAsync();
  42 +```
  43 +
  44 +### 3. 添加详细日志
  45 +- 添加计算开始日志
  46 +- 添加关键门店计算日志
  47 +- 添加更新前/后的值对比日志
  48 +- 添加跳过更新的警告日志
  49 +
  50 +### 4. 强制更新UpdateTime
  51 +```csharp
  52 +salary.UpdateTime = DateTime.Now; // 强制更新UpdateTime
  53 +```
  54 +
  55 +## 修改的文件
  56 +
  57 +### `LqTechGeneralManagerSalaryService.cs`
  58 +1. **行236**:修复日志中的时间格式化
  59 +2. **行330-331**:在循环外部定义时间格式化字符串
  60 +3. **行333-342**:修复溯源金额SQL的时间格式化
  61 +4. **行357-374**:修复Cell金额SQL的时间格式化,并添加调试日志
  62 +5. **行547**:添加跳过更新的警告日志
  63 +6. **行559**:强制设置UpdateTime
  64 +7. **行559-562**:添加IgnoreColumns确保强制更新
  65 +
  66 +## 验证步骤
  67 +
  68 +### 1. 重新编译(已完成)
  69 +```bash
  70 +cd netcore
  71 +dotnet clean src/Application/NCC.API/NCC.API.csproj
  72 +dotnet build src/Application/NCC.API/NCC.API.csproj
  73 +```
  74 +**结果**:编译成功 ✅
  75 +
  76 +### 2. 重启服务(必须执行)
  77 +⚠️ **重要**:代码修改后必须完全重启服务才能生效
  78 +
  79 +### 3. 调用计算接口
  80 +```bash
  81 +POST /api/Extend/lqtechgeneralmanagersalary/calculate/tech-general-manager?year=2025&month=12
  82 +```
  83 +
  84 +### 4. 验证结果
  85 +```sql
  86 +SELECT F_EmployeeName, F_StatisticsMonth, F_CellAmount, F_UpdateTime
  87 +FROM lq_tech_general_manager_salary_statistics
  88 +WHERE F_EmployeeName LIKE '%夏萍%' AND F_StatisticsMonth = '202512'
  89 +```
  90 +
  91 +**预期结果**:
  92 +- Cell金额:**69,838.00** 元
  93 +- UpdateTime:当前时间
  94 +
  95 +## 门店明细预期值
  96 +
  97 +| 门店ID | 门店名称 | 当前值 | 预期值 | 差异 |
  98 +|--------|---------|--------|--------|------|
  99 +| 1649328471923847173 | 绿纤静居寺店 | 37,400.00 | 46,110.00 | +8,710.00 |
  100 +| 1649328471923847175 | 绿纤468店 | 66.30 | 0.00 | -66.30 |
  101 +| 1649328471923847187 | 绿纤明信店 | 2,000.00 | 2,200.00 | +200.00 |
  102 +
  103 +**合计差异**:+8,843.70 元
  104 +
  105 +## 注意事项
  106 +
  107 +1. **服务重启**:代码修改后必须完全重启服务才能生效
  108 +2. **日志查看**:查看服务日志中是否有 "已更新 X 条科技部总经理工资记录" 的日志
  109 +3. **数据验证**:验证UpdateTime是否更新为当前时间
  110 +4. **对比验证**:Cell金额应该与 `/api/Extend/LqTechDepartmentDashboard/GetStatistics` 接口返回的值一致
  111 +
  112 +## 当前状态
  113 +
  114 +- ✅ 代码已修复
  115 +- ✅ 编译成功
  116 +- ⚠️ **需要重启服务并重新测试**
  117 +
  118 +## 下一步操作
  119 +
  120 +1. **重启服务**(必须)
  121 +2. **调用计算接口**进行测试
  122 +3. **验证数据库结果**是否更新为69,838.00
  123 +4. **查看服务日志**确认是否有错误信息
... ...
docs/test-reports/科技部总经理Cell金额计算问题诊断.md 0 → 100644
  1 +# 科技部总经理Cell金额计算问题诊断
  2 +
  3 +## 问题描述
  4 +重启服务并重新计算后,Cell金额仍然是 **60,994.30**,而不是预期的 **69,838.00**。
  5 +
  6 +## 诊断结果
  7 +
  8 +### 1. SQL查询是正确的
  9 +直接查询数据库,使用正确的SQL和时间范围,结果正确:
  10 +```sql
  11 +SELECT COALESCE(SUM(CAST(jksyj AS DECIMAL(18,2))), 0) as Amount
  12 +FROM lq_kd_jksyj
  13 +WHERE F_IsEffective = 1
  14 + AND F_StoreId IN (...)
  15 + AND (F_BeautyType = 'cell' OR F_BeautyType = 'Cell')
  16 + AND yjsj >= '2025-12-01 00:00:00'
  17 + AND yjsj <= '2025-12-31 23:59:59'
  18 +```
  19 +
  20 +**查询结果**:69,838.00 元(正确)
  21 +
  22 +### 2. 代码逻辑检查
  23 +- ✅ `endDateTime` 变量已正确定义
  24 +- ✅ SQL字符串格式化正确
  25 +- ✅ 使用原生SQL在数据库层面转换
  26 +- ✅ 时间范围处理正确
  27 +
  28 +### 3. 问题定位
  29 +**可能的原因**:SqlSugar 的 `Updateable` 默认只更新有变化的字段。如果计算出来的值与数据库中的值相同(或接近),可能不会触发更新。
  30 +
  31 +**解决方案**:添加 `IgnoreColumns` 确保强制更新所有字段(已添加)
  32 +
  33 +## 已修复的问题
  34 +
  35 +### 1. 添加了 IgnoreColumns
  36 +```csharp
  37 +await _db.Updateable(recordsToUpdate)
  38 + .IgnoreColumns(x => x.CreateTime)
  39 + .IgnoreColumns(x => x.CreateUser)
  40 + .ExecuteCommandAsync();
  41 +```
  42 +
  43 +### 2. 添加了日志记录
  44 +```csharp
  45 +_logger.LogInformation($"已更新 {recordsToUpdate.Count} 条科技部总经理工资记录(月份:{monthStr})");
  46 +```
  47 +
  48 +## 验证步骤
  49 +
  50 +### 1. 重新编译和重启服务
  51 +```bash
  52 +cd netcore
  53 +dotnet build
  54 +# 重启服务
  55 +```
  56 +
  57 +### 2. 重新执行计算
  58 +```bash
  59 +POST /api/Extend/lqtechgeneralmanagersalary/calculate/tech-general-manager?year=2025&month=12
  60 +```
  61 +
  62 +### 3. 验证结果
  63 +```sql
  64 +SELECT F_EmployeeName, F_StatisticsMonth, F_CellAmount, F_UpdateTime
  65 +FROM lq_tech_general_manager_salary_statistics
  66 +WHERE F_EmployeeName LIKE '%夏萍%' AND F_StatisticsMonth = '202512'
  67 +```
  68 +
  69 +**预期结果**:
  70 +- Cell金额:**69,838.00** 元
  71 +- UpdateTime:当前时间
  72 +
  73 +## 门店明细预期值
  74 +
  75 +| 门店ID | 门店名称 | 预期Cell金额 |
  76 +|--------|---------|------------|
  77 +| 1649328471923847170 | 绿纤龙湖店 | 7,140.00 |
  78 +| 1649328471923847172 | 绿纤华润店 | 5,500.00 |
  79 +| 1649328471923847173 | 绿纤静居寺店 | **46,110.00** (当前:37,400.00) |
  80 +| 1649328471923847184 | 绿纤大丰店 | 8,888.00 |
  81 +| 1649328471923847187 | 绿纤明信店 | **2,200.00** (当前:2,000.00) |
  82 +| 1649328471923847175 | 绿纤468店 | **0.00** (当前:66.30) |
  83 +
  84 +## 注意事项
  85 +
  86 +1. **确保服务已重启**:代码修改后必须重启服务才能生效
  87 +2. **检查日志**:查看是否有 "已更新 X 条科技部总经理工资记录" 的日志
  88 +3. **验证更新时间**:F_UpdateTime 应该更新为当前时间
  89 +4. **对比科技部驾驶舱接口**:Cell金额应该与 `/api/Extend/LqTechDepartmentDashboard/GetStatistics` 接口返回的值一致
... ...
docs/科技部总经理Cell金额差异分析.md 0 → 100644
  1 +# 科技部总经理Cell金额差异分析
  2 +
  3 +## 问题描述
  4 +
  5 +**夏萍**(科技部总经理)在 **202512** 月份的Cell金额存在差异:
  6 +- **工资表中**:60994.30 元
  7 +- **科技部驾驶舱接口**(`/api/Extend/LqTechDepartmentDashboard/GetStatistics`):69838.00 元
  8 +- **差异**:8843.70 元
  9 +
  10 +## 差异原因分析
  11 +
  12 +### 1. 门店范围不同
  13 +
  14 +#### 工资计算接口(`LqTechGeneralManagerSalaryService`)
  15 +- **数据来源**:`lq_mdxx` 表的 `kjb` 字段
  16 +- **逻辑**:通过门店的 `kjb` 字段等于科技部组织ID来确定管理的门店
  17 +- **门店数量**:16个门店
  18 +
  19 +#### 科技部驾驶舱接口(`LqTechDepartmentDashboardService`)
  20 +- **数据来源**:`lq_md_target` 表的 `F_TechDepartment` 字段
  21 +- **逻辑**:通过 `lq_md_target` 表查询指定月份、指定科技部归属的门店列表
  22 +- **门店数量**:18个门店
  23 +
  24 +#### 差异门店
  25 +- **只在 `lq_md_target` 中存在的门店**:
  26 + 1. `1649328471923847197` - 绿纤龙城国际店(`kjb` = `734725628560934149`,不是 `734725579919590661`)
  27 + 2. `766197905571710213` - 绿纤西站店(`kjb` = `null`)
  28 +
  29 +这两个门店在工资计算时**不包含**,但在科技部驾驶舱接口中**包含**。
  30 +
  31 +### 2. 时间范围处理差异
  32 +
  33 +#### 工资计算接口
  34 +```csharp
  35 +var startDate = new DateTime(year, month, 1);
  36 +var endDate = startDate.AddMonths(1).AddDays(-1);
  37 +// 开单时间:x.Yjsj >= startDate && x.Yjsj <= endDate.AddDays(1)
  38 +// 退卡时间:x.Tksj >= startDate && x.Tksj <= endDate.AddDays(1)
  39 +```
  40 +
  41 +#### 科技部驾驶舱接口
  42 +```csharp
  43 +var startDate = new DateTime(year, month, 1);
  44 +var endDate = startDate.AddMonths(1).AddDays(-1);
  45 +var endDateTime = input.StatisticsMonth == DateTime.Now.ToString("yyyyMM")
  46 + ? DateTime.Now
  47 + : endDate.Date.AddHours(23).AddMinutes(59).AddSeconds(59);
  48 +// 开单时间:yjsj >= '{startDate:yyyy-MM-dd HH:mm:ss}' AND yjsj <= '{endDateTime:yyyy-MM-dd HH:mm:ss}'
  49 +// 退卡时间:x.Tksj.Value.Date >= startDate.Date && x.Tksj.Value.Date <= endDate.Date
  50 +```
  51 +
  52 +**差异**:
  53 +- 工资计算接口:退卡时间使用 `endDate.AddDays(1)`(包含下个月第一天)
  54 +- 科技部驾驶舱接口:退卡时间使用 `endDate.Date`(只到当月最后一天)
  55 +
  56 +### 3. 数据查询方式差异
  57 +
  58 +#### 工资计算接口
  59 +- 使用 **SqlSugar ORM** 查询
  60 +- 开单Cell金额:先查询所有记录到内存,然后解析字符串 `jksyj` 字段并求和
  61 +- 退卡Cell金额:直接使用 `SumAsync` 聚合查询
  62 +
  63 +#### 科技部驾驶舱接口
  64 +- 使用 **原生SQL** 查询
  65 +- 开单Cell金额:使用 `CAST(jksyj AS DECIMAL(18,2))` 在数据库层面转换并求和
  66 +- 退卡Cell金额:使用 `SumAsync` 聚合查询
  67 +
  68 +## 验证结果
  69 +
  70 +### 工资表中的门店明细(16个门店)
  71 +```
  72 +绿纤龙湖店: 7140.0
  73 +绿纤华润店: 5500.0
  74 +绿纤静居寺店: 37400.0
  75 +绿纤468店: 66.3
  76 +绿纤大丰店: 8888.0
  77 +绿纤明信店: 2000.0
  78 +其他门店: 0.0
  79 +合计: 60994.3
  80 +```
  81 +
  82 +### 差异明细(使用lq_md_target的门店范围查询)
  83 +
  84 +| 门店ID | 门店名称 | 工资表金额 | 驾驶舱金额 | 差异 |
  85 +|--------|---------|-----------|-----------|------|
  86 +| 1649328471923847173 | 绿纤静居寺店 | 37,400.00 | 46,110.00 | **+8,710.00** |
  87 +| 1649328471923847175 | 绿纤468店 | 66.30 | 0.00 | **-66.30** |
  88 +| 1649328471923847187 | 绿纤明信店 | 2,000.00 | 2,200.00 | **+200.00** |
  89 +| **合计** | | **60,994.30** | **69,838.00** | **+8,843.70** |
  90 +
  91 +### 差异原因分析
  92 +
  93 +#### 1. 时间范围差异(主要原因)
  94 +
  95 +**工资计算接口**:
  96 +```csharp
  97 +x.Yjsj >= startDate && x.Yjsj <= endDate.AddDays(1)
  98 +// 即:yjsj >= '2025-12-01' AND yjsj <= '2026-01-01'
  99 +```
  100 +
  101 +**科技部驾驶舱接口**:
  102 +```csharp
  103 +yjsj >= '{startDate:yyyy-MM-dd HH:mm:ss}' AND yjsj <= '{endDateTime:yyyy-MM-dd HH:mm:ss}'
  104 +// 即:yjsj >= '2025-12-01 00:00:00' AND yjsj <= '2025-12-31 23:59:59'
  105 +```
  106 +
  107 +**关键差异**:
  108 +- 工资计算接口:包含 **2026-01-01** 的数据(跨月数据)
  109 +- 科技部驾驶舱接口:只包含 **2025-12-31** 及之前的数据
  110 +
  111 +这导致工资计算接口可能包含了部分下个月的数据,而科技部驾驶舱接口严格按照当月范围。
  112 +
  113 +#### 2. 数据查询方式差异
  114 +
  115 +**工资计算接口**:
  116 +- 使用 SqlSugar ORM,先查询所有记录到内存
  117 +- 然后使用 `decimal.TryParse` 解析字符串 `jksyj` 字段
  118 +- 可能存在精度问题或解析失败的情况
  119 +
  120 +**科技部驾驶舱接口**:
  121 +- 使用原生SQL,在数据库层面使用 `CAST(jksyj AS DECIMAL(18,2))` 转换
  122 +- 直接在数据库层面求和,精度更高
  123 +
  124 +#### 3. 门店范围差异
  125 +
  126 +- 工资计算接口:使用 `lq_mdxx.kjb` 字段(16个门店)
  127 +- 科技部驾驶舱接口:使用 `lq_md_target.F_TechDepartment` 字段(18个门店)
  128 +- 但额外2个门店的Cell金额为0,不影响差异
  129 +
  130 +## 结论
  131 +
  132 +**夏萍的Cell金额差异8843.70元主要来自:**
  133 +
  134 +1. **时间范围差异**(主要原因):
  135 + - 工资计算接口包含 `endDate.AddDays(1)`(即2026-01-01的数据)
  136 + - 科技部驾驶舱接口只包含当月数据(2025-12-31及之前)
  137 + - 这导致工资计算接口可能包含了部分下个月的数据
  138 +
  139 +2. **数据查询方式差异**:
  140 + - 工资计算接口使用内存解析字符串,可能存在精度问题
  141 + - 科技部驾驶舱接口使用数据库层面转换,精度更高
  142 +
  143 +3. **门店范围差异**:
  144 + - 两个接口使用不同的数据源确定门店范围
  145 + - 但额外门店的Cell金额为0,不影响差异
  146 +
  147 +## 建议
  148 +
  149 +### 1. 统一时间范围(最重要)
  150 +- **推荐**:两个接口都使用 `endDate.Date.AddHours(23).AddMinutes(59).AddSeconds(59)`
  151 +- 确保不包含下个月的数据,严格按照当月范围计算
  152 +
  153 +### 2. 统一数据查询方式
  154 +- **推荐**:工资计算接口改为使用原生SQL查询,在数据库层面转换和求和
  155 +- 确保计算精度一致,避免内存解析导致的精度问题
  156 +
  157 +### 3. 统一门店范围
  158 +- **推荐**:工资计算接口改为使用 `lq_md_target` 表确定门店范围
  159 +- 这样可以确保两个接口使用相同的门店范围,便于数据核对
  160 +
  161 +### 4. 数据验证结果
  162 +
  163 +**2026-01-01当天的Cell金额:18,446.00元**
  164 +
  165 +| 门店ID | 门店名称 | 2026-01-01 Cell金额 |
  166 +|--------|---------|-------------------|
  167 +| 1649328471923847172 | 绿纤华润店 | 198.00 |
  168 +| 1649328471923847173 | 绿纤静居寺店 | 10,360.00 |
  169 +| 1649328471923847187 | 绿纤明信店 | 7,000.00 |
  170 +| 1649328471923847192 | 绿纤凤凰山店 | 888.00 |
  171 +
  172 +**分析**:
  173 +- 工资计算接口使用 `endDate.AddDays(1)`,包含了2026-01-01的数据
  174 +- 科技部驾驶舱接口只包含2025-12-31及之前的数据
  175 +- 但差异8843.70元 < 2026-01-01的18446.00元,说明还有其他因素
  176 +
  177 +**进一步分析**:
  178 +- 工资计算接口可能使用了不同的数据解析方式,导致部分数据未正确计算
  179 +- 建议重新计算工资,使用与科技部驾驶舱接口相同的时间范围和查询方式
... ...
scripts/test/test_tech_gm_cell_amount.sh 0 → 100755
  1 +#!/bin/bash
  2 +
  3 +echo "=== 测试科技部总经理Cell金额计算 ==="
  4 +echo ""
  5 +
  6 +# 1. 获取Token
  7 +echo "1. 获取Token..."
  8 +TOKEN=$(curl -s -X POST "http://localhost:2011/api/oauth/Login" \
  9 + -H "Content-Type: application/x-www-form-urlencoded" \
  10 + -d "account=admin&password=e10adc3949ba59abbe56e057f20f883e" | \
  11 + python3 -c "import sys, json; data = json.load(sys.stdin); print(data.get('data', {}).get('token', ''))")
  12 +
  13 +if [ -z "$TOKEN" ]; then
  14 + echo "❌ 获取Token失败"
  15 + exit 1
  16 +fi
  17 +echo "✅ Token获取成功"
  18 +echo ""
  19 +
  20 +# 2. 查询计算前的数据
  21 +echo "2. 查询计算前的数据..."
  22 +BEFORE_CELL=$(mysql -h127.0.0.1 -uroot -p123456 lqerp_dev -sN -e \
  23 + "SELECT F_CellAmount FROM lq_tech_general_manager_salary_statistics WHERE F_EmployeeName LIKE '%夏萍%' AND F_StatisticsMonth = '202512'")
  24 +BEFORE_UPDATE_TIME=$(mysql -h127.0.0.1 -uroot -p123456 lqerp_dev -sN -e \
  25 + "SELECT F_UpdateTime FROM lq_tech_general_manager_salary_statistics WHERE F_EmployeeName LIKE '%夏萍%' AND F_StatisticsMonth = '202512'")
  26 +echo "计算前 Cell金额: $BEFORE_CELL"
  27 +echo "计算前 UpdateTime: $BEFORE_UPDATE_TIME"
  28 +echo ""
  29 +
  30 +# 3. 调用计算接口
  31 +echo "3. 调用计算接口..."
  32 +RESULT=$(curl -s -X POST "http://localhost:2011/api/Extend/lqtechgeneralmanagersalary/calculate/tech-general-manager?year=2025&month=12" \
  33 + -H "Authorization: $TOKEN")
  34 +echo "响应: $RESULT"
  35 +echo ""
  36 +
  37 +# 4. 等待2秒
  38 +echo "4. 等待2秒..."
  39 +sleep 2
  40 +echo ""
  41 +
  42 +# 5. 查询计算后的数据
  43 +echo "5. 查询计算后的数据..."
  44 +AFTER_CELL=$(mysql -h127.0.0.1 -uroot -p123456 lqerp_dev -sN -e \
  45 + "SELECT F_CellAmount FROM lq_tech_general_manager_salary_statistics WHERE F_EmployeeName LIKE '%夏萍%' AND F_StatisticsMonth = '202512'")
  46 +AFTER_UPDATE_TIME=$(mysql -h127.0.0.1 -uroot -p123456 lqerp_dev -sN -e \
  47 + "SELECT F_UpdateTime FROM lq_tech_general_manager_salary_statistics WHERE F_EmployeeName LIKE '%夏萍%' AND F_StatisticsMonth = '202512'")
  48 +echo "计算后 Cell金额: $AFTER_CELL"
  49 +echo "计算后 UpdateTime: $AFTER_UPDATE_TIME"
  50 +echo ""
  51 +
  52 +# 6. 验证结果
  53 +echo "6. 验证结果..."
  54 +EXPECTED_CELL="69838.00"
  55 +if [ "$AFTER_CELL" == "$EXPECTED_CELL" ]; then
  56 + echo "✅ Cell金额正确: $AFTER_CELL (预期: $EXPECTED_CELL)"
  57 +else
  58 + echo "❌ Cell金额不正确: $AFTER_CELL (预期: $EXPECTED_CELL)"
  59 +fi
  60 +
  61 +if [ "$AFTER_UPDATE_TIME" != "$BEFORE_UPDATE_TIME" ]; then
  62 + echo "✅ UpdateTime已更新"
  63 +else
  64 + echo "⚠️ UpdateTime未更新"
  65 +fi
  66 +echo ""
  67 +
  68 +# 7. 查询门店明细
  69 +echo "7. 查询门店明细..."
  70 +mysql -h127.0.0.1 -uroot -p123456 lqerp_dev -e \
  71 + "SELECT JSON_EXTRACT(F_StoreDetail, '\$[2].StoreName') as StoreName, \
  72 + JSON_EXTRACT(F_StoreDetail, '\$[2].CellAmount') as CellAmount \
  73 + FROM lq_tech_general_manager_salary_statistics \
  74 + WHERE F_EmployeeName LIKE '%夏萍%' AND F_StatisticsMonth = '202512'"
  75 +echo ""
  76 +
  77 +echo "=== 测试完成 ==="
... ...
scripts/test/test_tech_gm_cell_amount_final.sh 0 → 100755
  1 +#!/bin/bash
  2 +
  3 +echo "=== 科技部总经理Cell金额计算完整测试 ==="
  4 +echo ""
  5 +
  6 +# 1. 获取Token
  7 +echo "1. 获取Token..."
  8 +TOKEN=$(curl -s -X POST "http://localhost:2011/api/oauth/Login" \
  9 + -H "Content-Type: application/x-www-form-urlencoded" \
  10 + -d "account=admin&password=e10adc3949ba59abbe56e057f20f883e" | \
  11 + python3 -c "import sys, json; data = json.load(sys.stdin); print(data.get('data', {}).get('token', ''))")
  12 +
  13 +if [ -z "$TOKEN" ]; then
  14 + echo "❌ 获取Token失败"
  15 + exit 1
  16 +fi
  17 +echo "✅ Token获取成功: ${TOKEN:0:50}..."
  18 +echo ""
  19 +
  20 +# 2. 查询计算前的数据
  21 +echo "2. 查询计算前的数据..."
  22 +BEFORE_CELL=$(mysql -h127.0.0.1 -uroot -p123456 lqerp_dev -sN -e \
  23 + "SELECT F_CellAmount FROM lq_tech_general_manager_salary_statistics WHERE F_EmployeeName LIKE '%夏萍%' AND F_StatisticsMonth = '202512'")
  24 +BEFORE_UPDATE_TIME=$(mysql -h127.0.0.1 -uroot -p123456 lqerp_dev -sN -e \
  25 + "SELECT F_UpdateTime FROM lq_tech_general_manager_salary_statistics WHERE F_EmployeeName LIKE '%夏萍%' AND F_StatisticsMonth = '202512'")
  26 +echo "计算前 Cell金额: $BEFORE_CELL"
  27 +echo "计算前 UpdateTime: $BEFORE_UPDATE_TIME"
  28 +echo ""
  29 +
  30 +# 3. 调用计算接口
  31 +echo "3. 调用计算接口..."
  32 +RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}" -X POST \
  33 + "http://localhost:2011/api/Extend/lqtechgeneralmanagersalary/calculate/tech-general-manager?year=2025&month=12" \
  34 + -H "Authorization: $TOKEN")
  35 +HTTP_CODE=$(echo "$RESPONSE" | grep "HTTP_CODE" | cut -d: -f2)
  36 +BODY=$(echo "$RESPONSE" | sed '/HTTP_CODE/d')
  37 +
  38 +echo "HTTP状态码: $HTTP_CODE"
  39 +if [ "$HTTP_CODE" = "200" ]; then
  40 + echo "响应: $BODY" | python3 -m json.tool 2>/dev/null || echo "响应: $BODY"
  41 +else
  42 + echo "❌ 接口调用失败"
  43 + echo "响应: $BODY"
  44 +fi
  45 +echo ""
  46 +
  47 +# 4. 等待3秒
  48 +echo "4. 等待3秒..."
  49 +sleep 3
  50 +echo ""
  51 +
  52 +# 5. 查询计算后的数据
  53 +echo "5. 查询计算后的数据..."
  54 +AFTER_CELL=$(mysql -h127.0.0.1 -uroot -p123456 lqerp_dev -sN -e \
  55 + "SELECT F_CellAmount FROM lq_tech_general_manager_salary_statistics WHERE F_EmployeeName LIKE '%夏萍%' AND F_StatisticsMonth = '202512'")
  56 +AFTER_UPDATE_TIME=$(mysql -h127.0.0.1 -uroot -p123456 lqerp_dev -sN -e \
  57 + "SELECT F_UpdateTime FROM lq_tech_general_manager_salary_statistics WHERE F_EmployeeName LIKE '%夏萍%' AND F_StatisticsMonth = '202512'")
  58 +echo "计算后 Cell金额: $AFTER_CELL"
  59 +echo "计算后 UpdateTime: $AFTER_UPDATE_TIME"
  60 +echo ""
  61 +
  62 +# 6. 验证结果
  63 +echo "6. 验证结果..."
  64 +EXPECTED_CELL="69838.00"
  65 +if [ "$AFTER_CELL" = "$EXPECTED_CELL" ]; then
  66 + echo "✅ Cell金额正确: $AFTER_CELL (预期: $EXPECTED_CELL)"
  67 +else
  68 + echo "❌ Cell金额不正确: $AFTER_CELL (预期: $EXPECTED_CELL)"
  69 +fi
  70 +
  71 +if [ "$AFTER_UPDATE_TIME" != "$BEFORE_UPDATE_TIME" ]; then
  72 + echo "✅ UpdateTime已更新"
  73 +else
  74 + echo "⚠️ UpdateTime未更新"
  75 +fi
  76 +echo ""
  77 +
  78 +echo "=== 测试完成 ==="
... ...