207c283a
“wangming”
优化财务报表页面UI样式,修复健康...
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
|
# 健康师薪酬计算规则梳理 - 额外数据与金三角战队业绩整合逻辑
## 一、核心问题
健康师的额外数据(`lq_salary_extra_calculation` 表)会影响健康师的业绩计算,变动后的业绩需要整合到金三角战队业绩中。
## 二、数据流程梳理
### 2.1 数据来源
#### 1. 基础业绩数据
- **表名**: `lq_kd_jksyj` (健康师业绩表)
- **字段**:
- `jkszh`: 健康师账号/ID
- `jksyj`: 健康师业绩(字符串类型,需转换)
- `PerformanceType`: 业绩类型("基础业绩" 或 "合作业绩")
- `yjsj`: 业绩时间
- `glkdbh`: 关联开单编号
#### 2. 额外计算数据
- **表名**: `lq_salary_extra_calculation` (健康师工资额外计算表)
- **关键字段**:
- `F_EmployeeId`: 健康师ID
- `F_Year`: 年份
- `F_Month`: 月份
- `F_BaseRewardPerformance`: 基础奖励业绩(需从基础业绩中扣除)
- `F_CooperationRewardPerformance`: 合作奖励业绩(需从合作业绩中扣除)
- `F_OtherPerformanceAdd`: **其他业绩加**(需加到总业绩中)
- `F_OtherPerformanceSubtract`: **其他业绩减**(需从总业绩中扣除)
- `F_NewCustomerPerformance`: 新客业绩(可能被额外数据覆盖)
- `F_UpgradePerformance`: 升单业绩(可能被额外数据覆盖)
#### 3. 退款数据
- **表名**: `lq_hytk_jksyj` (退款健康师业绩表)
- **作用**: 从总业绩中扣除退款金额
#### 4. 金三角战队数据
- **表名**: `lq_jinsanjiao_user` (金三角用户表)
- **表名**: `lq_ycsd_jsj` (金三角基础信息表)
- **作用**: 确定健康师所属的战队
### 2.2 当前计算流程(代码位置:`LqSalaryService.cs` 的 `CalculateHealthCoachSalary` 方法)
#### 步骤1: 计算基础业绩数据(第563-591行)
```csharp
// 2.1 计算个人业绩
var myPerf = performanceData.Where(x => x.Jks == empId).ToList();
salary.BasePerformance = myPerf.Where(x => (x.PerformanceType ?? "").Trim() == "基础业绩")
.Sum(x => decimal.Parse(x.Jksyj ?? "0"));
salary.CooperationPerformance = myPerf.Where(x => (x.PerformanceType ?? "").Trim() == "合作业绩")
.Sum(x => decimal.Parse(x.Jksyj ?? "0"));
salary.TotalPerformance = myPerf.Sum(x => decimal.Parse(x.Jksyj ?? "0")); // 第567行
// 扣除退款
var myRefunds = refundList.Where(x => x.Jks == empId).ToList();
if (myRefunds.Any())
{
decimal totalRefund = myRefunds.Sum(x => x.Jksyj ?? 0);
salary.TotalPerformance -= totalRefund; // 第584行
salary.BasePerformance -= baseRefund;
salary.CooperationPerformance -= cooperationRefund;
}
// 新客与升单业绩(从开单记录中统计)
salary.NewCustomerPerformance = myPerf.Where(x => string.Equals(x.Sfskdd, "是"))
.Sum(x => decimal.Parse(x.Jksyj ?? "0"));
salary.UpgradePerformance = myPerf.Where(x => string.Equals(x.Sfskdd, "否"))
.Sum(x => decimal.Parse(x.Jksyj ?? "0"));
```
**当前问题**:
- `TotalPerformance` 只统计了开单业绩并扣除了退款
- **没有加上 `OtherPerformanceAdd`**
- **没有减去 `OtherPerformanceSubtract`**
#### 步骤2: 填充额外计算数据(第593-605行)
```csharp
// 2.1.1 填充额外计算数据
if (extraCalculationDict.ContainsKey(empId))
{
var extraData = extraCalculationDict[empId];
salary.BaseRewardPerformance = extraData.BaseRewardPerformance;
salary.CooperationRewardPerformance = extraData.CooperationRewardPerformance;
salary.OtherPerformanceAdd = extraData.OtherPerformanceAdd; // 第599行
salary.OtherPerformanceSubtract = extraData.OtherPerformanceSubtract; // 第600行
salary.UpgradeCustomerCount = extraData.UpgradeCustomerCount;
salary.NewCustomerConversionRate = extraData.NewCustomerConversionRate;
salary.NewCustomerPerformance = extraData.NewCustomerPerformance; // 可能覆盖之前的值
salary.UpgradePerformance = extraData.UpgradePerformance; // 可能覆盖之前的值
}
```
**说明**:
- 额外数据被填充到工资统计对象中
- `NewCustomerPerformance` 和 `UpgradePerformance` 可能被额外数据覆盖
#### 步骤3: 计算实际基础业绩和实际合作业绩(第607-636行)
```csharp
// 2.1.2 计算实际基础业绩和实际合作业绩
// 实际基础业绩 = 基础业绩 - 基础奖励业绩 + 其他业绩加 - 其他业绩减
decimal actualBasePerformance = salary.BasePerformance
- salary.BaseRewardPerformance
+ salary.OtherPerformanceAdd // 第615行:只影响实际基础业绩
- salary.OtherPerformanceSubtract; // 第616行:只影响实际基础业绩
// 新店额外调整:根据阶段扣除新客业绩或升单业绩
if (isNewStore)
{
if (newStoreStage == 1)
{
actualBasePerformance -= salary.NewCustomerPerformance;
}
else if (newStoreStage == 2)
{
actualBasePerformance -= salary.UpgradePerformance;
}
}
salary.ActualBasePerformance = actualBasePerformance;
// 实际合作业绩 = 合作业绩 - 合作奖励业绩
salary.ActualCooperationPerformance = salary.CooperationPerformance - salary.CooperationRewardPerformance;
```
**当前问题**:
- `OtherPerformanceAdd` 和 `OtherPerformanceSubtract` **只用于计算 `ActualBasePerformance`**
- **没有用于调整 `TotalPerformance`**
#### 步骤4: 计算金三角战队业绩(第700-753行)
```csharp
// 3. 处理战队逻辑 (考勤规则)
// 规则:若出勤天数 < 20天,则该健康师不计入战队,按单人计算。
// 按战队分组
var teamGroups = employeeStats.Values
.Where(x => !string.IsNullOrEmpty(x.GoldTriangleId))
.GroupBy(x => x.GoldTriangleId)
.ToList();
foreach (var group in teamGroups)
{
var validMembers = new List<LqSalaryStatisticsEntity>();
var invalidMembers = new List<LqSalaryStatisticsEntity>();
foreach (var member in group)
{
if (member.WorkingDays >= 20)
{
validMembers.Add(member);
}
else
{
invalidMembers.Add(member);
}
}
// 对于无效成员,移除战队标识,视为单人
foreach (var member in invalidMembers)
{
member.GoldTriangleId = null;
member.GoldTriangleTeam = "个人";
member.Position = "健康师";
}
// 计算有效战队的总业绩和总消耗
var teamTotalPerformance = validMembers.Sum(x => x.TotalPerformance); // 第735行
var teamTotalConsumption = validMembers.Sum(x => x.Consumption);
// 更新有效成员的战队业绩和战队总消耗
foreach (var member in validMembers)
{
member.TeamPerformance = teamTotalPerformance; // 第741行
member.TeamTotalConsumption = teamTotalConsumption;
}
}
// 补充处理:对于没有战队ID的(个人,或被剔除的),战队业绩等于个人总业绩
foreach (var salary in employeeStats.Values)
{
if (string.IsNullOrEmpty(salary.GoldTriangleId))
{
salary.TeamPerformance = salary.TotalPerformance; // 第751行
}
}
```
**当前问题**:
- 第735行计算战队总业绩时,使用的是 `x.TotalPerformance`
- 但 `TotalPerformance` **没有包含额外数据的调整**(`OtherPerformanceAdd` 和 `OtherPerformanceSubtract`)
- 因此,**金三角战队业绩没有整合变动后的业绩**
## 三、问题分析
### 3.1 核心问题
1. **总业绩未包含额外数据调整**
- `TotalPerformance` 只统计了开单业绩并扣除了退款
- 没有加上 `OtherPerformanceAdd`
- 没有减去 `OtherPerformanceSubtract`
2. **金三角战队业绩计算不准确**
- 战队业绩 = 所有有效成员的总业绩之和
- 但使用的是未调整的 `TotalPerformance`
- 导致额外数据的变动没有反映到战队业绩中
### 3.2 影响范围
1. **健康师个人总业绩**: 不准确(缺少额外数据调整)
2. **金三角战队业绩**: 不准确(基于不准确的个人总业绩)
3. **提成计算**: 可能受影响(如果提成计算依赖 `TotalPerformance`)
4. **业绩占比**: 不准确(个人业绩占比 = 个人总业绩 / 战队总业绩)
## 四、解决方案建议
### 4.1 方案一:在计算总业绩时直接加上额外数据调整
**修改位置**: `LqSalaryService.cs` 第567-605行
**修改逻辑**:
```csharp
// 2.1 计算个人业绩
var myPerf = performanceData.Where(x => x.Jks == empId).ToList();
salary.BasePerformance = myPerf.Where(x => (x.PerformanceType ?? "").Trim() == "基础业绩")
.Sum(x => decimal.Parse(x.Jksyj ?? "0"));
salary.CooperationPerformance = myPerf.Where(x => (x.PerformanceType ?? "").Trim() == "合作业绩")
.Sum(x => decimal.Parse(x.Jksyj ?? "0"));
salary.TotalPerformance = myPerf.Sum(x => decimal.Parse(x.Jksyj ?? "0"));
// 扣除退款
var myRefunds = refundList.Where(x => x.Jks == empId).ToList();
if (myRefunds.Any())
{
decimal totalRefund = myRefunds.Sum(x => x.Jksyj ?? 0);
salary.TotalPerformance -= totalRefund;
salary.BasePerformance -= baseRefund;
salary.CooperationPerformance -= cooperationRefund;
}
// 新客与升单业绩(从开单记录中统计)
salary.NewCustomerPerformance = myPerf.Where(x => string.Equals(x.Sfskdd, "是"))
.Sum(x => decimal.Parse(x.Jksyj ?? "0"));
salary.UpgradePerformance = myPerf.Where(x => string.Equals(x.Sfskdd, "否"))
.Sum(x => decimal.Parse(x.Jksyj ?? "0"));
// 2.1.1 填充额外计算数据
if (extraCalculationDict.ContainsKey(empId))
{
var extraData = extraCalculationDict[empId];
salary.BaseRewardPerformance = extraData.BaseRewardPerformance;
salary.CooperationRewardPerformance = extraData.CooperationRewardPerformance;
salary.OtherPerformanceAdd = extraData.OtherPerformanceAdd;
salary.OtherPerformanceSubtract = extraData.OtherPerformanceSubtract;
salary.UpgradeCustomerCount = extraData.UpgradeCustomerCount;
salary.NewCustomerConversionRate = extraData.NewCustomerConversionRate;
salary.NewCustomerPerformance = extraData.NewCustomerPerformance;
salary.UpgradePerformance = extraData.UpgradePerformance;
// 【新增】调整总业绩:加上其他业绩加,减去其他业绩减
salary.TotalPerformance += salary.OtherPerformanceAdd;
salary.TotalPerformance -= salary.OtherPerformanceSubtract;
}
```
**优点**:
- 简单直接,在填充额外数据后立即调整总业绩
- 确保后续所有使用 `TotalPerformance` 的地方都能获取到调整后的值
**缺点**:
- 需要确认 `OtherPerformanceAdd` 和 `OtherPerformanceSubtract` 是否应该影响总业绩
- 需要确认是否应该影响基础业绩或合作业绩
### 4.2 方案二:在计算战队业绩前调整总业绩
**修改位置**: `LqSalaryService.cs` 第700-753行
**修改逻辑**:
```csharp
// 3. 处理战队逻辑 (考勤规则)
// 规则:若出勤天数 < 20天,则该健康师不计入战队,按单人计算。
// 【新增】在计算战队业绩前,先调整所有健康师的总业绩(加上额外数据)
foreach (var salary in employeeStats.Values)
{
salary.TotalPerformance += salary.OtherPerformanceAdd;
salary.TotalPerformance -= salary.OtherPerformanceSubtract;
}
// 按战队分组
var teamGroups = employeeStats.Values
.Where(x => !string.IsNullOrEmpty(x.GoldTriangleId))
.GroupBy(x => x.GoldTriangleId)
.ToList();
// ... 后续逻辑不变
```
**优点**:
- 集中处理,逻辑清晰
- 确保在计算战队业绩前,所有成员的总业绩都已调整
**缺点**:
- 如果其他地方也使用 `TotalPerformance`,可能也需要调整
### 4.3 方案三:使用调整后的总业绩字段
**修改逻辑**:
- 保持 `TotalPerformance` 不变(原始总业绩)
- 新增 `AdjustedTotalPerformance` 字段(调整后的总业绩)
- 在计算战队业绩时使用 `AdjustedTotalPerformance`
**优点**:
- 保留原始数据,便于追溯
- 明确区分原始业绩和调整后业绩
**缺点**:
- 需要修改数据库表结构
- 需要修改所有使用总业绩的地方
## 五、推荐方案
**推荐使用方案一**,原因:
1. 逻辑简单,在填充额外数据后立即调整总业绩
2. 确保后续所有使用 `TotalPerformance` 的地方都能获取到调整后的值
3. 不需要修改数据库表结构
4. 符合业务逻辑:额外数据应该影响总业绩
## 六、需要确认的问题
1. **`OtherPerformanceAdd` 和 `OtherPerformanceSubtract` 是否应该影响总业绩?**
- 当前代码中,这两个字段只影响 `ActualBasePerformance`
- 需要确认业务规则:是否应该同时影响 `TotalPerformance`
2. **额外数据中的 `NewCustomerPerformance` 和 `UpgradePerformance` 是否应该覆盖从开单记录中统计的值?**
- 当前代码中,如果存在额外数据,会覆盖之前统计的值
- 需要确认业务规则:是覆盖还是累加?
3. **额外数据是否应该影响基础业绩或合作业绩?**
- 当前代码中,`OtherPerformanceAdd` 和 `OtherPerformanceSubtract` 只影响 `ActualBasePerformance`
- 需要确认:是否应该同时调整 `BasePerformance` 或 `CooperationPerformance`?
4. **金三角战队业绩的计算时机**
- 当前在计算战队业绩时,使用的是 `TotalPerformance`
- 如果 `TotalPerformance` 没有包含额外数据调整,战队业绩就不准确
- 需要确认:是否应该在计算战队业绩前,先调整所有成员的总业绩?
## 七、代码修改建议
### 7.1 修改位置
**文件**: `netcore/src/Modularity/Extend/NCC.Extend/LqSalaryService.cs`
**方法**: `CalculateHealthCoachSalary`
**位置**: 第593-605行(填充额外计算数据后)
### 7.2 修改内容
在填充额外计算数据后,立即调整总业绩:
```csharp
// 2.1.1 填充额外计算数据
if (extraCalculationDict.ContainsKey(empId))
{
var extraData = extraCalculationDict[empId];
salary.BaseRewardPerformance = extraData.BaseRewardPerformance;
salary.CooperationRewardPerformance = extraData.CooperationRewardPerformance;
salary.OtherPerformanceAdd = extraData.OtherPerformanceAdd;
salary.OtherPerformanceSubtract = extraData.OtherPerformanceSubtract;
salary.UpgradeCustomerCount = extraData.UpgradeCustomerCount;
salary.NewCustomerConversionRate = extraData.NewCustomerConversionRate;
salary.NewCustomerPerformance = extraData.NewCustomerPerformance;
salary.UpgradePerformance = extraData.UpgradePerformance;
// 【新增】调整总业绩:加上其他业绩加,减去其他业绩减
// 注意:这里调整的是总业绩,确保后续计算(包括战队业绩)使用的是调整后的值
salary.TotalPerformance += salary.OtherPerformanceAdd;
salary.TotalPerformance -= salary.OtherPerformanceSubtract;
}
```
### 7.3 影响分析
**修改后的影响**:
1. ✅ 健康师个人总业绩包含额外数据调整
2. ✅ 金三角战队业绩 = 所有有效成员的调整后总业绩之和
3. ✅ 提成计算(如果依赖 `TotalPerformance`)会使用调整后的值
4. ✅ 业绩占比计算会使用调整后的值
**需要注意**:
- 确保 `OtherPerformanceAdd` 和 `OtherPerformanceSubtract` 的值是正确的
- 确保额外数据表(`lq_salary_extra_calculation`)的数据是准确的
- 如果后续有其他地方也使用 `TotalPerformance`,需要确认是否应该使用调整后的值
## 八、测试建议
1. **单元测试**:
- 测试额外数据为0时,总业绩不变
- 测试 `OtherPerformanceAdd > 0` 时,总业绩增加
- 测试 `OtherPerformanceSubtract > 0` 时,总业绩减少
- 测试两者同时存在时的计算
2. **集成测试**:
- 测试单个健康师的额外数据调整后,总业绩是否正确
- 测试战队中多个成员都有额外数据时,战队总业绩是否正确
- 测试战队中部分成员有额外数据时,战队总业绩是否正确
3. **数据验证**:
- 对比修改前后的计算结果
- 验证金三角战队业绩是否包含额外数据调整
- 验证业绩占比计算是否正确
---
**文档版本**: v1.0
**创建日期**: 2026-01-09
**适用范围**: 健康师薪酬计算 - 额外数据与金三角战队业绩整合
|