Commit 15ec2754380f2e7727326806c3aa795559826c40
1 parent
9790054f
feat: 优化统计功能
- 修复GetStoreDailyStatistics和GetStorePerformanceCompletion,只统计zxzt为'开店'的门店 - 为GetBusinessUnitPerformanceCompletion和GetTianwangGroupPerformanceCompletion添加退卡业绩统计和实际完成业绩计算 - 为GetEmployeePerformanceStatistics添加手工费统计和消耗项目数分类统计(原始、加班、陪同) - 修复ConsumeCount和RefundCount统计逻辑,改为统计消耗单数和退卡单数
Showing
6 changed files
with
249 additions
and
66 deletions
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/BusinessUnitPerformanceCompletionOutput.cs
| ... | ... | @@ -24,12 +24,27 @@ namespace NCC.Extend.Entitys.Dto.LqDailyReport |
| 24 | 24 | public decimal TargetPerformance { get; set; } |
| 25 | 25 | |
| 26 | 26 | /// <summary> |
| 27 | - /// 完成业绩(管理门店的开单业绩总和) | |
| 27 | + /// 开单业绩(管理门店的开单业绩总和) | |
| 28 | + /// </summary> | |
| 29 | + public decimal BillingPerformance { get; set; } | |
| 30 | + | |
| 31 | + /// <summary> | |
| 32 | + /// 退款业绩(退卡业绩总和) | |
| 33 | + /// </summary> | |
| 34 | + public decimal RefundPerformance { get; set; } | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 开单业绩(管理门店的开单业绩总和) | |
| 38 | + /// </summary> | |
| 39 | + public decimal ActualPerformance { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 实际完成业绩(开单业绩 - 退款业绩) | |
| 28 | 43 | /// </summary> |
| 29 | 44 | public decimal CompletedPerformance { get; set; } |
| 30 | 45 | |
| 31 | 46 | /// <summary> |
| 32 | - /// 完成率(百分比) | |
| 47 | + /// 完成率(百分比,基于实际完成业绩计算) | |
| 33 | 48 | /// </summary> |
| 34 | 49 | public decimal CompletionRate { get; set; } |
| 35 | 50 | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqDailyReport/TianwangGroupPerformanceCompletionOutput.cs
| ... | ... | @@ -24,12 +24,27 @@ namespace NCC.Extend.Entitys.Dto.LqDailyReport |
| 24 | 24 | public decimal TargetPerformance { get; set; } |
| 25 | 25 | |
| 26 | 26 | /// <summary> |
| 27 | - /// 完成业绩(管理门店的开单业绩总和) | |
| 27 | + /// 开单业绩(管理门店的开单业绩总和) | |
| 28 | + /// </summary> | |
| 29 | + public decimal BillingPerformance { get; set; } | |
| 30 | + | |
| 31 | + /// <summary> | |
| 32 | + /// 退款业绩(退卡业绩总和) | |
| 33 | + /// </summary> | |
| 34 | + public decimal RefundPerformance { get; set; } | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 开单业绩(与BillingPerformance相同,用于兼容) | |
| 38 | + /// </summary> | |
| 39 | + public decimal ActualPerformance { get; set; } | |
| 40 | + | |
| 41 | + /// <summary> | |
| 42 | + /// 实际完成业绩(开单业绩 - 退款业绩) | |
| 28 | 43 | /// </summary> |
| 29 | 44 | public decimal CompletedPerformance { get; set; } |
| 30 | 45 | |
| 31 | 46 | /// <summary> |
| 32 | - /// 完成率(百分比) | |
| 47 | + /// 完成率(百分比,基于实际完成业绩计算) | |
| 33 | 48 | /// </summary> |
| 34 | 49 | public decimal CompletionRate { get; set; } |
| 35 | 50 | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqStatistics/EmployeePerformanceStatisticsOutput.cs
| ... | ... | @@ -41,7 +41,7 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics |
| 41 | 41 | public decimal BillingAmount { get; set; } |
| 42 | 42 | |
| 43 | 43 | /// <summary> |
| 44 | - /// 消耗数量 | |
| 44 | + /// 消耗单数(消耗主表的去重记录数) | |
| 45 | 45 | /// </summary> |
| 46 | 46 | public int ConsumeCount { get; set; } |
| 47 | 47 | |
| ... | ... | @@ -51,7 +51,7 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics |
| 51 | 51 | public decimal ConsumeAmount { get; set; } |
| 52 | 52 | |
| 53 | 53 | /// <summary> |
| 54 | - /// 退卡数量 | |
| 54 | + /// 退卡单数量(退卡主表的去重记录数) | |
| 55 | 55 | /// </summary> |
| 56 | 56 | public int RefundCount { get; set; } |
| 57 | 57 | |
| ... | ... | @@ -76,8 +76,28 @@ namespace NCC.Extend.Entitys.Dto.LqStatistics |
| 76 | 76 | public int BillingProjectCount { get; set; } |
| 77 | 77 | |
| 78 | 78 | /// <summary> |
| 79 | - /// 消耗项目数(项目次数总和) | |
| 79 | + /// 消耗项目数(项目次数总和,包含原始+加班+陪同) | |
| 80 | 80 | /// </summary> |
| 81 | 81 | public int ConsumeProjectCount { get; set; } |
| 82 | + | |
| 83 | + /// <summary> | |
| 84 | + /// 消耗原始项目数(原始项目次数总和) | |
| 85 | + /// </summary> | |
| 86 | + public decimal ConsumeOriginalProjectCount { get; set; } | |
| 87 | + | |
| 88 | + /// <summary> | |
| 89 | + /// 消耗加班项目数(加班项目次数总和) | |
| 90 | + /// </summary> | |
| 91 | + public decimal ConsumeOvertimeProjectCount { get; set; } | |
| 92 | + | |
| 93 | + /// <summary> | |
| 94 | + /// 消耗陪同项目数(陪同项目次数总和) | |
| 95 | + /// </summary> | |
| 96 | + public decimal ConsumeAccompaniedProjectCount { get; set; } | |
| 97 | + | |
| 98 | + /// <summary> | |
| 99 | + /// 手工费(消耗手工费总和) | |
| 100 | + /// </summary> | |
| 101 | + public decimal LaborCost { get; set; } | |
| 82 | 102 | } |
| 83 | 103 | } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqDailyReportService.cs
| ... | ... | @@ -125,7 +125,7 @@ namespace NCC.Extend |
| 125 | 125 | storeFilter = $"AND consume.Md IN ('{storeIdsStr}')"; |
| 126 | 126 | } |
| 127 | 127 | |
| 128 | - // SQL查询:获取门店每日运营数据 | |
| 128 | + // SQL查询:获取门店每日运营数据(只统计zxzt为"开店"的门店) | |
| 129 | 129 | var sql = $@" |
| 130 | 130 | SELECT |
| 131 | 131 | consume.Md as StoreId, |
| ... | ... | @@ -148,7 +148,7 @@ namespace NCC.Extend |
| 148 | 148 | -- 消耗业绩(总金额) |
| 149 | 149 | COALESCE(SUM(project.F_TotalPrice), 0) as ConsumePerformance |
| 150 | 150 | FROM lq_xh_hyhk consume |
| 151 | - LEFT JOIN lq_mdxx store ON consume.Md = store.F_Id | |
| 151 | + INNER JOIN lq_mdxx store ON consume.Md = store.F_Id AND store.zxzt = '开店' | |
| 152 | 152 | LEFT JOIN lq_xh_pxmx project ON consume.F_Id = project.F_ConsumeInfoId AND project.F_IsEffective = 1 |
| 153 | 153 | WHERE consume.F_IsEffective = 1 |
| 154 | 154 | AND DATE(consume.Hksj) >= '{startDate:yyyy-MM-dd}' |
| ... | ... | @@ -227,7 +227,7 @@ namespace NCC.Extend |
| 227 | 227 | storeFilter = $"AND store.F_Id IN ('{storeIdsStr}')"; |
| 228 | 228 | } |
| 229 | 229 | |
| 230 | - // SQL查询:获取门店业绩完成情况 | |
| 230 | + // SQL查询:获取门店业绩完成情况(只统计zxzt为"开店"的门店) | |
| 231 | 231 | var sql = $@" |
| 232 | 232 | SELECT |
| 233 | 233 | store.F_Id as StoreId, |
| ... | ... | @@ -254,7 +254,7 @@ namespace NCC.Extend |
| 254 | 254 | ), 0) as RefundPerformance |
| 255 | 255 | FROM lq_mdxx store |
| 256 | 256 | LEFT JOIN lq_md_target target ON target.F_StoreId = store.F_Id AND target.F_Month = '{month}' |
| 257 | - WHERE 1=1 {storeFilter} | |
| 257 | + WHERE store.zxzt = '开店' {storeFilter} | |
| 258 | 258 | ORDER BY (BillingPerformance - RefundPerformance) DESC"; |
| 259 | 259 | |
| 260 | 260 | var result = await _db.Ado.SqlQueryAsync<dynamic>(sql); |
| ... | ... | @@ -289,7 +289,7 @@ namespace NCC.Extend |
| 289 | 289 | /// 获取事业部业绩完成情况 |
| 290 | 290 | /// </summary> |
| 291 | 291 | /// <remarks> |
| 292 | - /// 根据指定日期统计各事业部的业绩完成情况,包括目标业绩、完成业绩、完成率 | |
| 292 | + /// 根据指定日期统计各事业部的业绩完成情况,包括目标业绩、开单业绩、退卡金额、实际完成业绩、完成率 | |
| 293 | 293 | /// |
| 294 | 294 | /// 示例请求: |
| 295 | 295 | /// ```json |
| ... | ... | @@ -309,7 +309,10 @@ namespace NCC.Extend |
| 309 | 309 | /// - BusinessUnitId: 事业部ID |
| 310 | 310 | /// - BusinessUnitName: 事业部名称 |
| 311 | 311 | /// - TargetPerformance: 目标业绩(来自门店目标表lq_md_target的F_BusinessUnitTarget字段,根据开始时间所在月份获取,通过F_BusinessUnit字段关联,如果未查询到则为0) |
| 312 | - /// - CompletedPerformance: 完成业绩(指定时间范围内的开单业绩总和) | |
| 312 | + /// - BillingPerformance: 开单业绩(指定时间范围内的开单业绩总和) | |
| 313 | + /// - RefundPerformance: 退款业绩(指定时间范围内的退卡业绩总和) | |
| 314 | + /// - ActualPerformance: 开单业绩(与BillingPerformance相同,用于兼容) | |
| 315 | + /// - CompletedPerformance: 实际完成业绩(开单业绩 - 退款业绩) | |
| 313 | 316 | /// - CompletionRate: 完成率(百分比,CompletedPerformance / TargetPerformance * 100) |
| 314 | 317 | /// - StoreCount: 门店数量(根据门店目标表中归属该事业部的门店数统计) |
| 315 | 318 | /// </remarks> |
| ... | ... | @@ -368,20 +371,23 @@ namespace NCC.Extend |
| 368 | 371 | BusinessUnitId = unit.BusinessUnitId.ToString(), |
| 369 | 372 | BusinessUnitName = unit.BusinessUnitName.ToString(), |
| 370 | 373 | TargetPerformance = Convert.ToDecimal(unit.TargetPerformance), |
| 374 | + BillingPerformance = 0, | |
| 375 | + RefundPerformance = 0, | |
| 376 | + ActualPerformance = 0, | |
| 371 | 377 | CompletedPerformance = 0, |
| 372 | 378 | CompletionRate = 0, |
| 373 | 379 | StoreCount = Convert.ToInt32(unit.StoreCount) |
| 374 | 380 | }; |
| 375 | 381 | } |
| 376 | 382 | |
| 377 | - // 第二步:统计各事业部的完成业绩 | |
| 383 | + // 第二步:统计各事业部的开单业绩 | |
| 378 | 384 | var businessUnitIds = businessUnitDict.Keys.ToList(); |
| 379 | 385 | var unitIdsStr = string.Join("','", businessUnitIds); |
| 380 | 386 | |
| 381 | - var completedPerformanceSql = $@" | |
| 387 | + var billingPerformanceSql = $@" | |
| 382 | 388 | SELECT |
| 383 | 389 | store.syb as BusinessUnitId, |
| 384 | - COALESCE(SUM(billing.sfyj), 0) as CompletedPerformance | |
| 390 | + COALESCE(SUM(billing.sfyj), 0) as BillingPerformance | |
| 385 | 391 | FROM lq_kd_kdjlb billing |
| 386 | 392 | INNER JOIN lq_mdxx store ON billing.djmd = store.F_Id |
| 387 | 393 | INNER JOIN base_organize o ON store.syb = o.F_Id |
| ... | ... | @@ -394,28 +400,58 @@ namespace NCC.Extend |
| 394 | 400 | AND store.syb IN ('{unitIdsStr}') |
| 395 | 401 | GROUP BY store.syb"; |
| 396 | 402 | |
| 397 | - var completedPerformanceData = await _db.Ado.SqlQueryAsync<dynamic>(completedPerformanceSql); | |
| 403 | + var billingPerformanceData = await _db.Ado.SqlQueryAsync<dynamic>(billingPerformanceSql); | |
| 404 | + | |
| 405 | + // 第三步:统计各事业部的退卡金额 | |
| 406 | + var refundPerformanceSql = $@" | |
| 407 | + SELECT | |
| 408 | + store.syb as BusinessUnitId, | |
| 409 | + COALESCE(SUM(refund.F_ActualRefundAmount), 0) as RefundPerformance | |
| 410 | + FROM lq_hytk_hytk refund | |
| 411 | + INNER JOIN lq_mdxx store ON refund.md = store.F_Id | |
| 412 | + INNER JOIN base_organize o ON store.syb = o.F_Id | |
| 413 | + WHERE refund.F_IsEffective = 1 | |
| 414 | + AND o.F_Category = 'department' | |
| 415 | + AND (o.F_DeleteMark IS NULL OR o.F_DeleteMark != 1) | |
| 416 | + AND o.F_FullName IN ('事业一部', '事业二部', '事业三部', '事业四部', '事业五部', '事业六部') | |
| 417 | + AND DATE(refund.tksj) >= '{startDate:yyyy-MM-dd}' | |
| 418 | + AND DATE(refund.tksj) <= '{endDate:yyyy-MM-dd}' | |
| 419 | + AND store.syb IN ('{unitIdsStr}') | |
| 420 | + GROUP BY store.syb"; | |
| 421 | + | |
| 422 | + var refundPerformanceData = await _db.Ado.SqlQueryAsync<dynamic>(refundPerformanceSql); | |
| 398 | 423 | |
| 399 | - // 第三步:合并数据并计算完成率 | |
| 400 | - foreach (var item in completedPerformanceData) | |
| 424 | + // 第四步:合并开单业绩数据 | |
| 425 | + foreach (var item in billingPerformanceData) | |
| 401 | 426 | { |
| 402 | 427 | var businessUnitId = item.BusinessUnitId.ToString(); |
| 403 | 428 | if (businessUnitDict.ContainsKey(businessUnitId)) |
| 404 | 429 | { |
| 405 | - var completedPerformance = Convert.ToDecimal(item.CompletedPerformance); | |
| 406 | - var unit = businessUnitDict[businessUnitId]; | |
| 407 | - unit.CompletedPerformance = completedPerformance; | |
| 408 | - | |
| 409 | - var completionRate = unit.TargetPerformance > 0 | |
| 410 | - ? (completedPerformance / unit.TargetPerformance * 100m) | |
| 411 | - : 0m; | |
| 412 | - unit.CompletionRate = decimal.Round(completionRate, 2); | |
| 430 | + businessUnitDict[businessUnitId].BillingPerformance = Convert.ToDecimal(item.BillingPerformance); | |
| 413 | 431 | } |
| 414 | 432 | } |
| 415 | 433 | |
| 416 | - var outputList = businessUnitDict.Values | |
| 417 | - .OrderByDescending(x => x.CompletedPerformance) | |
| 418 | - .ToList(); | |
| 434 | + // 第五步:合并退卡金额数据 | |
| 435 | + foreach (var item in refundPerformanceData) | |
| 436 | + { | |
| 437 | + var businessUnitId = item.BusinessUnitId.ToString(); | |
| 438 | + if (businessUnitDict.ContainsKey(businessUnitId)) | |
| 439 | + { | |
| 440 | + businessUnitDict[businessUnitId].RefundPerformance = Convert.ToDecimal(item.RefundPerformance); | |
| 441 | + } | |
| 442 | + } | |
| 443 | + | |
| 444 | + // 第六步:计算实际完成业绩和完成率 | |
| 445 | + foreach (var unit in businessUnitDict.Values) | |
| 446 | + { | |
| 447 | + unit.ActualPerformance = unit.BillingPerformance; // 开单业绩 | |
| 448 | + var actualCompletedPerformance = unit.BillingPerformance - unit.RefundPerformance; // 实际完成业绩 | |
| 449 | + unit.CompletedPerformance = actualCompletedPerformance; // 实际完成业绩 | |
| 450 | + var completionRate = unit.TargetPerformance > 0 ? (actualCompletedPerformance / unit.TargetPerformance * 100m) : 0m; | |
| 451 | + unit.CompletionRate = decimal.Round(completionRate, 2); | |
| 452 | + } | |
| 453 | + | |
| 454 | + var outputList = businessUnitDict.Values.OrderByDescending(x => x.CompletedPerformance).ToList(); | |
| 419 | 455 | |
| 420 | 456 | return outputList; |
| 421 | 457 | } |
| ... | ... | @@ -426,7 +462,7 @@ namespace NCC.Extend |
| 426 | 462 | /// 获取天王团业绩完成情况 |
| 427 | 463 | /// </summary> |
| 428 | 464 | /// <remarks> |
| 429 | - /// 根据指定日期统计各天王团的业绩完成情况,包括目标业绩、完成业绩、完成率 | |
| 465 | + /// 根据指定日期统计各天王团的业绩完成情况,包括目标业绩、开单业绩、退卡金额、实际完成业绩、完成率 | |
| 430 | 466 | /// |
| 431 | 467 | /// 示例请求: |
| 432 | 468 | /// ```json |
| ... | ... | @@ -446,7 +482,10 @@ namespace NCC.Extend |
| 446 | 482 | /// - DepartmentId: 部门ID |
| 447 | 483 | /// - DepartmentName: 部门名称(教育一部、教育二部、科技一部、科技二部、大项目一部、大项目二部) |
| 448 | 484 | /// - TargetPerformance: 目标业绩(来自门店目标表lq_md_target,根据部门类型使用对应字段:教育部使用F_EducationDepartmentTarget,科技部使用F_TechDepartmentTarget,大项目部使用F_MajorProjectDepartmentTarget,根据开始时间所在月份获取,通过对应归属字段关联,如果未查询到则为0) |
| 449 | - /// - CompletedPerformance: 完成业绩(指定时间范围内的开单业绩总和) | |
| 485 | + /// - BillingPerformance: 开单业绩(指定时间范围内的开单业绩总和) | |
| 486 | + /// - RefundPerformance: 退款业绩(指定时间范围内的退卡业绩总和) | |
| 487 | + /// - ActualPerformance: 开单业绩(与BillingPerformance相同,用于兼容) | |
| 488 | + /// - CompletedPerformance: 实际完成业绩(开单业绩 - 退款业绩) | |
| 450 | 489 | /// - CompletionRate: 完成率(百分比,CompletedPerformance / TargetPerformance * 100) |
| 451 | 490 | /// - StoreCount: 门店数量(根据门店目标表中归属该部门的门店数统计) |
| 452 | 491 | /// </remarks> |
| ... | ... | @@ -517,6 +556,9 @@ namespace NCC.Extend |
| 517 | 556 | DepartmentId = dept.DepartmentId.ToString(), |
| 518 | 557 | DepartmentName = dept.DepartmentName.ToString(), |
| 519 | 558 | TargetPerformance = Convert.ToDecimal(dept.TargetPerformance), |
| 559 | + BillingPerformance = 0, | |
| 560 | + RefundPerformance = 0, | |
| 561 | + ActualPerformance = 0, | |
| 520 | 562 | CompletedPerformance = 0, |
| 521 | 563 | CompletionRate = 0, |
| 522 | 564 | StoreCount = Convert.ToInt32(dept.StoreCount) |
| ... | ... | @@ -530,14 +572,14 @@ namespace NCC.Extend |
| 530 | 572 | return new List<TianwangGroupPerformanceCompletionOutput>(); |
| 531 | 573 | } |
| 532 | 574 | |
| 533 | - // 第二步:统计各天王团的完成业绩(直接按部门ID统计,避免重复计算) | |
| 575 | + // 第二步:统计各天王团的开单业绩(直接按部门ID统计,避免重复计算) | |
| 534 | 576 | var deptIdsStrForQuery = string.Join("','", departmentDict.Keys); |
| 535 | 577 | |
| 536 | 578 | // 使用 OR 条件连接三个部门类型字段,确保每个开单记录只被统计一次到对应的部门 |
| 537 | - var completedPerformanceSql = $@" | |
| 579 | + var billingPerformanceSql = $@" | |
| 538 | 580 | SELECT |
| 539 | 581 | o.F_Id as DepartmentId, |
| 540 | - COALESCE(SUM(billing.sfyj), 0) as CompletedPerformance | |
| 582 | + COALESCE(SUM(billing.sfyj), 0) as BillingPerformance | |
| 541 | 583 | FROM lq_kd_kdjlb billing |
| 542 | 584 | INNER JOIN lq_mdxx store ON billing.djmd = store.F_Id |
| 543 | 585 | INNER JOIN base_organize o ON ( |
| ... | ... | @@ -553,35 +595,63 @@ namespace NCC.Extend |
| 553 | 595 | AND o.F_Id IN ('{deptIdsStrForQuery}') |
| 554 | 596 | GROUP BY o.F_Id"; |
| 555 | 597 | |
| 556 | - var completedPerformanceData = await _db.Ado.SqlQueryAsync<dynamic>(completedPerformanceSql); | |
| 598 | + var billingPerformanceData = await _db.Ado.SqlQueryAsync<dynamic>(billingPerformanceSql); | |
| 599 | + | |
| 600 | + // 第三步:统计各天王团的退卡金额 | |
| 601 | + var refundPerformanceSql = $@" | |
| 602 | + SELECT | |
| 603 | + o.F_Id as DepartmentId, | |
| 604 | + COALESCE(SUM(refund.F_ActualRefundAmount), 0) as RefundPerformance | |
| 605 | + FROM lq_hytk_hytk refund | |
| 606 | + INNER JOIN lq_mdxx store ON refund.md = store.F_Id | |
| 607 | + INNER JOIN base_organize o ON ( | |
| 608 | + (store.jyb = o.F_Id AND o.F_FullName IN ('教育一部', '教育二部')) | |
| 609 | + OR (store.kjb = o.F_Id AND o.F_FullName IN ('科技一部', '科技二部')) | |
| 610 | + OR (store.dxmb = o.F_Id AND o.F_FullName IN ('大项目一部', '大项目二部')) | |
| 611 | + ) | |
| 612 | + WHERE refund.F_IsEffective = 1 | |
| 613 | + AND o.F_Category = 'department' | |
| 614 | + AND (o.F_DeleteMark IS NULL OR o.F_DeleteMark != 1) | |
| 615 | + AND DATE(refund.tksj) >= '{startDate:yyyy-MM-dd}' | |
| 616 | + AND DATE(refund.tksj) <= '{endDate:yyyy-MM-dd}' | |
| 617 | + AND o.F_Id IN ('{deptIdsStrForQuery}') | |
| 618 | + GROUP BY o.F_Id"; | |
| 619 | + | |
| 620 | + var refundPerformanceData = await _db.Ado.SqlQueryAsync<dynamic>(refundPerformanceSql); | |
| 557 | 621 | |
| 558 | - // 第三步:将完成业绩数据填充到部门字典中 | |
| 559 | - var departmentPerformanceDict = new Dictionary<string, decimal>(); | |
| 560 | - if (completedPerformanceData != null) | |
| 622 | + // 第四步:合并开单业绩数据 | |
| 623 | + foreach (var item in billingPerformanceData ?? Enumerable.Empty<dynamic>()) | |
| 561 | 624 | { |
| 562 | - foreach (var item in completedPerformanceData) | |
| 625 | + var departmentId = item.DepartmentId.ToString(); | |
| 626 | + if (departmentDict.ContainsKey(departmentId)) | |
| 563 | 627 | { |
| 564 | - var departmentId = item.DepartmentId.ToString(); | |
| 565 | - var completedPerformance = Convert.ToDecimal(item.CompletedPerformance); | |
| 566 | - departmentPerformanceDict[departmentId] = completedPerformance; | |
| 628 | + departmentDict[departmentId].BillingPerformance = Convert.ToDecimal(item.BillingPerformance); | |
| 567 | 629 | } |
| 568 | 630 | } |
| 569 | 631 | |
| 570 | - // 计算完成率 | |
| 571 | - foreach (var kvp in departmentPerformanceDict) | |
| 632 | + // 第五步:合并退卡金额数据 | |
| 633 | + foreach (var item in refundPerformanceData ?? Enumerable.Empty<dynamic>()) | |
| 572 | 634 | { |
| 573 | - if (departmentDict.ContainsKey(kvp.Key)) | |
| 635 | + var departmentId = item.DepartmentId.ToString(); | |
| 636 | + if (departmentDict.ContainsKey(departmentId)) | |
| 574 | 637 | { |
| 575 | - var dept = departmentDict[kvp.Key]; | |
| 576 | - dept.CompletedPerformance = kvp.Value; | |
| 577 | - | |
| 578 | - var completionRate = dept.TargetPerformance > 0 | |
| 579 | - ? (kvp.Value / dept.TargetPerformance * 100m) | |
| 580 | - : 0m; | |
| 581 | - dept.CompletionRate = decimal.Round(completionRate, 2); | |
| 638 | + departmentDict[departmentId].RefundPerformance = Convert.ToDecimal(item.RefundPerformance); | |
| 582 | 639 | } |
| 583 | 640 | } |
| 584 | 641 | |
| 642 | + // 第六步:计算实际完成业绩和完成率 | |
| 643 | + foreach (var dept in departmentDict.Values) | |
| 644 | + { | |
| 645 | + dept.ActualPerformance = dept.BillingPerformance; // 开单业绩 | |
| 646 | + var actualCompletedPerformance = dept.BillingPerformance - dept.RefundPerformance; // 实际完成业绩 | |
| 647 | + dept.CompletedPerformance = actualCompletedPerformance; // 实际完成业绩 | |
| 648 | + | |
| 649 | + var completionRate = dept.TargetPerformance > 0 | |
| 650 | + ? (actualCompletedPerformance / dept.TargetPerformance * 100m) | |
| 651 | + : 0m; | |
| 652 | + dept.CompletionRate = decimal.Round(completionRate, 2); | |
| 653 | + } | |
| 654 | + | |
| 585 | 655 | var outputList = departmentDict.Values |
| 586 | 656 | .OrderByDescending(x => x.CompletedPerformance) |
| 587 | 657 | .ToList(); | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqMdxxService.cs
| ... | ... | @@ -361,6 +361,7 @@ namespace NCC.Extend.LqMdxx |
| 361 | 361 | public async Task<dynamic> GetSelector() |
| 362 | 362 | { |
| 363 | 363 | var list = await _db.Queryable<LqMdxxEntity>() |
| 364 | + .Where(it => it.Zxzt == "开店") | |
| 364 | 365 | .Select(it => new { id = it.Id, fullName = it.Dm, enCode = it.Mdbm }) |
| 365 | 366 | .ToListAsync(); |
| 366 | 367 | return new { list = list }; | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqStatisticsService.cs
| ... | ... | @@ -3495,13 +3495,17 @@ namespace NCC.Extend.LqStatistics |
| 3495 | 3495 | /// - BillingCount: 开单数量 |
| 3496 | 3496 | /// - BillingAmount: 开单金额 |
| 3497 | 3497 | /// - BillingProjectCount: 开单项目数(项目次数总和) |
| 3498 | - /// - ConsumeCount: 消耗数量 | |
| 3498 | + /// - ConsumeCount: 消耗单数(消耗主表的去重记录数) | |
| 3499 | 3499 | /// - ConsumeAmount: 消耗金额 |
| 3500 | - /// - ConsumeProjectCount: 消耗项目数(项目次数总和) | |
| 3501 | - /// - RefundCount: 退卡数量 | |
| 3500 | + /// - ConsumeProjectCount: 消耗项目数(项目次数总和,包含原始+加班+陪同) | |
| 3501 | + /// - ConsumeOriginalProjectCount: 消耗原始项目数(原始项目次数总和) | |
| 3502 | + /// - ConsumeOvertimeProjectCount: 消耗加班项目数(加班项目次数总和) | |
| 3503 | + /// - ConsumeAccompaniedProjectCount: 消耗陪同项目数(陪同项目次数总和) | |
| 3504 | + /// - RefundCount: 退卡单数量 | |
| 3502 | 3505 | /// - RefundAmount: 退卡金额 |
| 3503 | 3506 | /// - HeadCount: 人头(月度去重客户数) |
| 3504 | 3507 | /// - PersonCount: 人次(日度去重客户数) |
| 3508 | + /// - LaborCost: 手工费(消耗手工费总和) | |
| 3505 | 3509 | /// </remarks> |
| 3506 | 3510 | /// <param name="input">查询参数</param> |
| 3507 | 3511 | /// <returns>员工业绩统计数据</returns> |
| ... | ... | @@ -3549,8 +3553,11 @@ namespace NCC.Extend.LqStatistics |
| 3549 | 3553 | // 9. 开单项目数统计 |
| 3550 | 3554 | var billingProjectCount = await GetBillingProjectCount(input.UserId, statisticsMonth); |
| 3551 | 3555 | |
| 3552 | - // 10. 消耗项目数统计 | |
| 3553 | - var consumeProjectCount = await GetConsumeProjectCount(input.UserId, statisticsMonth); | |
| 3556 | + // 10. 消耗项目数统计(包含总项目数、原始项目数、加班项目数、陪同项目数) | |
| 3557 | + var consumeProjectStats = await GetConsumeProjectCountDetails(input.UserId, statisticsMonth); | |
| 3558 | + | |
| 3559 | + // 11. 手工费统计 | |
| 3560 | + var laborCost = await GetLaborCost(input.UserId, statisticsMonth); | |
| 3554 | 3561 | |
| 3555 | 3562 | return new EmployeePerformanceStatisticsOutput |
| 3556 | 3563 | { |
| ... | ... | @@ -3568,7 +3575,11 @@ namespace NCC.Extend.LqStatistics |
| 3568 | 3575 | HeadCount = headCount, |
| 3569 | 3576 | PersonCount = personCount, |
| 3570 | 3577 | BillingProjectCount = billingProjectCount, |
| 3571 | - ConsumeProjectCount = consumeProjectCount | |
| 3578 | + ConsumeProjectCount = consumeProjectStats.TotalCount, | |
| 3579 | + ConsumeOriginalProjectCount = consumeProjectStats.OriginalCount, | |
| 3580 | + ConsumeOvertimeProjectCount = consumeProjectStats.OvertimeCount, | |
| 3581 | + ConsumeAccompaniedProjectCount = consumeProjectStats.AccompaniedCount, | |
| 3582 | + LaborCost = laborCost | |
| 3572 | 3583 | }; |
| 3573 | 3584 | } |
| 3574 | 3585 | catch (Exception ex) |
| ... | ... | @@ -3647,9 +3658,10 @@ namespace NCC.Extend.LqStatistics |
| 3647 | 3658 | /// </summary> |
| 3648 | 3659 | private async Task<(int Count, decimal Amount)> GetConsumeStats(string userId, string month) |
| 3649 | 3660 | { |
| 3661 | + // 统计消耗单数(消耗主表的去重记录数)和消耗金额(健康师业绩总和) | |
| 3650 | 3662 | var sql = $@" |
| 3651 | 3663 | SELECT |
| 3652 | - COUNT(*) as Count, | |
| 3664 | + COUNT(DISTINCT hyhk.F_Id) as Count, | |
| 3653 | 3665 | COALESCE(SUM(jksyj.jksyj), 0) as Amount |
| 3654 | 3666 | FROM lq_xh_jksyj jksyj |
| 3655 | 3667 | INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id |
| ... | ... | @@ -3668,14 +3680,17 @@ namespace NCC.Extend.LqStatistics |
| 3668 | 3680 | /// </summary> |
| 3669 | 3681 | private async Task<(int Count, decimal Amount)> GetRefundStats(string userId, string month) |
| 3670 | 3682 | { |
| 3683 | + // 统计退卡单数(退卡主表的去重记录数)和退卡金额(健康师业绩总和) | |
| 3671 | 3684 | var sql = $@" |
| 3672 | 3685 | SELECT |
| 3673 | - COUNT(*) as Count, | |
| 3674 | - COALESCE(SUM(jksyj), 0) as Amount | |
| 3675 | - FROM lq_hytk_jksyj | |
| 3676 | - WHERE jkszh = '{userId}' | |
| 3677 | - AND F_IsEffective = 1 | |
| 3678 | - AND DATE_FORMAT(tksj, '%Y%m') = '{month}'"; | |
| 3686 | + COUNT(DISTINCT hytk.F_Id) as Count, | |
| 3687 | + COALESCE(SUM(jksyj.jksyj), 0) as Amount | |
| 3688 | + FROM lq_hytk_jksyj jksyj | |
| 3689 | + INNER JOIN lq_hytk_hytk hytk ON jksyj.gltkbh = hytk.F_Id | |
| 3690 | + WHERE jksyj.jkszh = '{userId}' | |
| 3691 | + AND jksyj.F_IsEffective = 1 | |
| 3692 | + AND hytk.F_IsEffective = 1 | |
| 3693 | + AND DATE_FORMAT(hytk.tksj, '%Y%m') = '{month}'"; | |
| 3679 | 3694 | |
| 3680 | 3695 | var result = await _db.Ado.SqlQueryAsync<dynamic>(sql); |
| 3681 | 3696 | var data = result.FirstOrDefault(); |
| ... | ... | @@ -3754,6 +3769,53 @@ namespace NCC.Extend.LqStatistics |
| 3754 | 3769 | return Convert.ToInt32(result.FirstOrDefault()?.Count ?? 0); |
| 3755 | 3770 | } |
| 3756 | 3771 | |
| 3772 | + /// <summary> | |
| 3773 | + /// 统计消耗项目数详情(包含总项目数、原始项目数、加班项目数、陪同项目数) | |
| 3774 | + /// </summary> | |
| 3775 | + private async Task<(int TotalCount, decimal OriginalCount, decimal OvertimeCount, decimal AccompaniedCount)> GetConsumeProjectCountDetails(string userId, string month) | |
| 3776 | + { | |
| 3777 | + var sql = $@" | |
| 3778 | + SELECT | |
| 3779 | + COALESCE(SUM(pxmx.F_ProjectNumber), 0) as TotalCount, | |
| 3780 | + COALESCE(SUM(COALESCE(pxmx.F_OriginalProjectNumber, pxmx.F_ProjectNumber)), 0) as OriginalCount, | |
| 3781 | + COALESCE(SUM(COALESCE(pxmx.F_OvertimeProjectNumber, 0)), 0) as OvertimeCount, | |
| 3782 | + COALESCE(SUM(COALESCE(jksyj.F_AccompaniedProjectNumber, 0)), 0) as AccompaniedCount | |
| 3783 | + FROM lq_xh_jksyj jksyj | |
| 3784 | + INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id | |
| 3785 | + INNER JOIN lq_xh_pxmx pxmx ON pxmx.F_ConsumeInfoId = hyhk.F_Id | |
| 3786 | + WHERE jksyj.jkszh = '{userId}' | |
| 3787 | + AND jksyj.F_IsEffective = 1 | |
| 3788 | + AND hyhk.F_IsEffective = 1 | |
| 3789 | + AND DATE_FORMAT(hyhk.hksj, '%Y%m') = '{month}'"; | |
| 3790 | + | |
| 3791 | + var result = await _db.Ado.SqlQueryAsync<dynamic>(sql); | |
| 3792 | + var data = result.FirstOrDefault(); | |
| 3793 | + return ( | |
| 3794 | + Convert.ToInt32(data?.TotalCount ?? 0), | |
| 3795 | + Convert.ToDecimal(data?.OriginalCount ?? 0), | |
| 3796 | + Convert.ToDecimal(data?.OvertimeCount ?? 0), | |
| 3797 | + Convert.ToDecimal(data?.AccompaniedCount ?? 0) | |
| 3798 | + ); | |
| 3799 | + } | |
| 3800 | + | |
| 3801 | + /// <summary> | |
| 3802 | + /// 统计手工费(消耗手工费总和) | |
| 3803 | + /// </summary> | |
| 3804 | + private async Task<decimal> GetLaborCost(string userId, string month) | |
| 3805 | + { | |
| 3806 | + var sql = $@" | |
| 3807 | + SELECT COALESCE(SUM(jksyj.F_LaborCost), 0) as LaborCost | |
| 3808 | + FROM lq_xh_jksyj jksyj | |
| 3809 | + INNER JOIN lq_xh_hyhk hyhk ON jksyj.glkdbh = hyhk.F_Id | |
| 3810 | + WHERE jksyj.jkszh = '{userId}' | |
| 3811 | + AND jksyj.F_IsEffective = 1 | |
| 3812 | + AND hyhk.F_IsEffective = 1 | |
| 3813 | + AND DATE_FORMAT(hyhk.hksj, '%Y%m') = '{month}'"; | |
| 3814 | + | |
| 3815 | + var result = await _db.Ado.SqlQueryAsync<dynamic>(sql); | |
| 3816 | + return Convert.ToDecimal(result.FirstOrDefault()?.LaborCost ?? 0); | |
| 3817 | + } | |
| 3818 | + | |
| 3757 | 3819 | #endregion |
| 3758 | 3820 | } |
| 3759 | 3821 | } | ... | ... |