初稿

parent 28e2c18b
......@@ -10,6 +10,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Performance.Infrastructure;
using Performance.DtoModels.Second;
namespace Performance.Api.Controllers
{
......@@ -20,6 +22,7 @@ namespace Performance.Api.Controllers
public class SecondAllotController : ControllerBase
{
private readonly ClaimService claimService;
private readonly AllotService _allotService;
private readonly SecondAllotService secondAllotService;
private readonly ResultComputeService resultComputeService;
private readonly SecondAllotDetails secondAllotDetails;
......@@ -27,6 +30,7 @@ public class SecondAllotController : ControllerBase
public SecondAllotController(
ClaimService claimService,
AllotService allotService,
SecondAllotService secondAllotService,
ResultComputeService resultComputeService,
SecondAllotDetails secondAllotDetails,
......@@ -34,6 +38,7 @@ RedistributionService redistributionService
)
{
this.claimService = claimService;
_allotService = allotService;
this.secondAllotService = secondAllotService;
this.resultComputeService = resultComputeService;
this.secondAllotDetails = secondAllotDetails;
......@@ -330,7 +335,7 @@ public ApiResponse SingleDelete([CustomizeValidator(RuleSet = "Delete"), FromBod
[Route("/api/second/audit/submit")]
public ApiResponse SubmitAudit(SubmitAuditRequest request)
{
var second = secondAllotService.GetSecondallot(request.SecondId);
var second = secondAllotService.GetSecondAllot(request.SecondId);
if (second == null)
return new ApiResponse(ResponseType.ParameterError, "二次绩效Id无效");
if (second.Status == 3)
......@@ -534,18 +539,144 @@ public ApiResponse AutoCompleteBodyData([FromRoute] int secondId, SecondEmployee
return new ApiResponse(ResponseType.OK, result);
}
#region 二次分配后台计算
/// <summary>
/// 二次绩效录入页面
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[Route("api/second/redistribution")]
[HttpGet]
public ApiResponse Redistribution([FromRoute] SecondLoadRequest request)
[Route("api/second/redistribution/load")]
[HttpPost]
public ApiResponse RedistributionLoad([FromBody] SecondLoadDto request)
{
var result = _redistributionService.Load(request.SecondId, request.ComputeMode);
if (!Enum.IsDefined(typeof(ComputeMode), request.ComputeMode))
throw new PerformanceException("暂不支持当前计算方式!");
var overrideMode = OverrideMode.Initial;
if (Enum.IsDefined(typeof(OverrideMode), request.OverrideMode))
overrideMode = (OverrideMode)request.OverrideMode;
var result = _redistributionService.Load(request.SecondId, (ComputeMode)request.ComputeMode, overrideMode);
return new ApiResponse(ResponseType.OK, result);
}
/// <summary>
/// 提交数据正确性检验
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[Route("api/second/redistribution/check")]
[HttpPost]
public ApiResponse RedistributionCheck([FromBody] SecondComputeDto request)
{
if (request?.Body == null)
throw new PerformanceException("提交空参数,无法查看计算结果!");
var second = secondAllotService.GetSecondAllot(request.SecondId);
if (second == null) throw new PerformanceException("参数SecondId无效!");
var allot = _allotService.GetAllot(second.AllotId.Value);
if (allot == null)
throw new PerformanceException("绩效记录不存在!");
// 年资职称绩效占比与工作量绩效占比 校验
var loads = _redistributionService.GetWorkLoads(allot.HospitalId, second.UnitType, second.Department);
var workloadGroups = _redistributionService.GetTopWorkloadBodyGroups(loads);
var seniorityTitlesAccountedPerformance = request.Head.GetValue(nameof(ag_headsource.SeniorityTitlesAccountedPerformance), 0m);
var workloadRatio = workloadGroups.Sum(w => request.Head.GetValue($"Workload_Ratio_{w.Name}", 0m));
if (seniorityTitlesAccountedPerformance + workloadRatio > 1)
throw new PerformanceException("年资职称绩效占比与工作量绩效占比总和,超过100%!");
else if (seniorityTitlesAccountedPerformance + workloadRatio < 1)
throw new PerformanceException("年资职称绩效占比与工作量绩效占比总和,不足100%!");
// 二次分配人员信息 校验
var result = _redistributionService.CheckData(second, request.Body);
return new ApiResponse(ResponseType.OK, result);
}
/// <summary>
/// 二次绩效录入页面
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[Route("api/second/redistribution/compute")]
[HttpPost]
public ApiResponse RedistributionCompute([FromBody] SecondComputeDto request)
{
if (!Enum.IsDefined(typeof(ComputeMode), request.ComputeMode))
throw new PerformanceException("暂不支持当前计算方式!");
if (request?.Body == null)
throw new PerformanceException("提交空参数,无法查看计算结果!");
var second = secondAllotService.GetSecondAllot(request.SecondId);
if (second == null) throw new PerformanceException("参数SecondId无效!");
var allot = _allotService.GetAllot(second.AllotId.Value);
if (allot == null)
throw new PerformanceException("绩效记录不存在!");
// 年资职称绩效占比与工作量绩效占比 校验
var loads = _redistributionService.GetWorkLoads(allot.HospitalId, second.UnitType, second.Department);
var workloadGroups = _redistributionService.GetTopWorkloadBodyGroups(loads);
var seniorityTitlesAccountedPerformance = request.Head.GetValue(nameof(ag_headsource.SeniorityTitlesAccountedPerformance), 0m);
var workloadRatio = workloadGroups.Sum(w => request.Head.GetValue($"Workload_Ratio_{w.Name}", 0m));
if (seniorityTitlesAccountedPerformance + workloadRatio > 1)
throw new PerformanceException("年资职称绩效占比与工作量绩效占比总和,超过100%!");
else if (seniorityTitlesAccountedPerformance + workloadRatio < 1)
throw new PerformanceException("年资职称绩效占比与工作量绩效占比总和,不足100%!");
// 二次分配人员信息 校验
var checkDatas = _redistributionService.CheckData(second, request.Body);
if (checkDatas != null && checkDatas.Any(w => w.Level == ResponseType.Error.ToString()))
return new ApiResponse(ResponseType.Fail, "数据验证未通过,请修复后查看计算结果!", checkDatas.Where(w => w.Level == ResponseType.Error.ToString()));
// 清理无效数据 没有Tab标签的数据才是要计算的数据
var cleanDatas = request.Body.Where(w => w.Count > 0 && w.GetValue(nameof(ResponseType), "") == ResponseType.OK.ToString()).ToList();
if (cleanDatas == null || cleanDatas.Count == 0)
throw new PerformanceException("提交参数都是无效数据,请重新填写数据后查看计算结果!");
// 计算提交数据结果
_redistributionService.ResultCompute((ComputeMode)request.ComputeMode, request.Head, cleanDatas, loads, workloadGroups);
// 补充医院其他绩效
_redistributionService.SupplementOtherPerfor(second, cleanDatas);
// 重算顶部医院其他绩效
_redistributionService.OverviewCalculate_OtherPerformance(request.Head, cleanDatas);
var dic = _redistributionService.GetTableHeaderDictionary(loads);
return new ApiResponse(ResponseType.OK, new { Head = request.Head, Body = cleanDatas, Dic = dic });
}
/// <summary>
/// 二次绩效保存
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[Route("api/second/redistribution/save")]
[HttpPost]
public ApiResponse RedistributionSave([FromBody] SecondComputeDto request)
{
secondAllotService.SaveSecondAllotData(request.SecondId, request);
return new ApiResponse(ResponseType.OK);
}
/// <summary>
/// 二次绩效提交
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[Route("api/second/redistribution/submit")]
[HttpPost]
public ApiResponse RedistributionSubmit([FromBody] SecondComputeDto request)
{
var second = secondAllotService.GetSecondAllot(request.SecondId);
if (second == null)
return new ApiResponse(ResponseType.ParameterError, "二次绩效Id无效");
if (second.Status == 3)
return new ApiResponse(ResponseType.Fail, "该绩效已\"审核通过\",无需再次提交");
var userid = claimService.GetUserId();
var result = secondAllotService.AuditSubmit(second, userid);
return result ? new ApiResponse(ResponseType.OK, "提交成功") : new ApiResponse(ResponseType.Fail, "提交失败");
}
#endregion
}
}
......@@ -1612,6 +1612,41 @@
</summary>
<returns></returns>
</member>
<member name="M:Performance.Api.Controllers.SecondAllotController.RedistributionLoad(Performance.DtoModels.SecondLoadDto)">
<summary>
二次绩效录入页面
</summary>
<param name="request"></param>
<returns></returns>
</member>
<member name="M:Performance.Api.Controllers.SecondAllotController.RedistributionCheck(Performance.DtoModels.SecondComputeDto)">
<summary>
提交数据正确性检验
</summary>
<param name="request"></param>
<returns></returns>
</member>
<member name="M:Performance.Api.Controllers.SecondAllotController.RedistributionCompute(Performance.DtoModels.SecondComputeDto)">
<summary>
二次绩效录入页面
</summary>
<param name="request"></param>
<returns></returns>
</member>
<member name="M:Performance.Api.Controllers.SecondAllotController.RedistributionSave(Performance.DtoModels.SecondComputeDto)">
<summary>
二次绩效保存
</summary>
<param name="request"></param>
<returns></returns>
</member>
<member name="M:Performance.Api.Controllers.SecondAllotController.RedistributionSubmit(Performance.DtoModels.SecondComputeDto)">
<summary>
二次绩效提交
</summary>
<param name="request"></param>
<returns></returns>
</member>
<member name="M:Performance.Api.Controllers.SheetController.SheetList(Performance.DtoModels.SheetRequest)">
<summary>
sheet 列表
......
......@@ -179,6 +179,12 @@
<member name="F:Performance.DtoModels.DataFormat.小数">
<summary> 小数 </summary>
</member>
<member name="F:Performance.DtoModels.DataFormat.小数1">
<summary> 小数 </summary>
</member>
<member name="F:Performance.DtoModels.DataFormat.整数">
<summary> 整数 </summary>
</member>
<member name="F:Performance.DtoModels.DataFormat.货币">
<summary> 货币 </summary>
</member>
......@@ -3755,6 +3761,56 @@
绩效系数
</summary>
</member>
<member name="T:Performance.DtoModels.Second.ComputeMode">
<summary>
二次分配计算方式
</summary>
</member>
<member name="F:Performance.DtoModels.Second.ComputeMode.NotCalculate">
<summary>
不计算
</summary>
</member>
<member name="F:Performance.DtoModels.Second.ComputeMode.Horizontal">
<summary>
横向计算
</summary>
</member>
<member name="F:Performance.DtoModels.Second.ComputeMode.Vertical">
<summary>
纵向计算
</summary>
</member>
<member name="T:Performance.DtoModels.Second.OverrideMode">
<summary>
人员带出方式 已保存,上次,字典,测算表
</summary>
</member>
<member name="F:Performance.DtoModels.Second.OverrideMode.Initial">
<summary>
初始化(用户保存后的数据)
</summary>
</member>
<member name="F:Performance.DtoModels.Second.OverrideMode.PrevSecondAllot">
<summary>
上一个二次绩效记录
</summary>
</member>
<member name="F:Performance.DtoModels.Second.OverrideMode.EmployeeDict">
<summary>
人员字典
</summary>
</member>
<member name="P:Performance.DtoModels.SecondLoadDto.ComputeMode">
<summary>
计算方式:1 不计算 2 横向计算 3 纵向计算
</summary>
</member>
<member name="P:Performance.DtoModels.SecondLoadDto.OverrideMode">
<summary>
数据加载方式:0 保存,1 上次,2 字典,3 测算表
</summary>
</member>
<member name="P:Performance.DtoModels.SelectionOptions.SelectionID">
<summary>
ID
......
......@@ -474,19 +474,9 @@
职称绩效
</summary>
</member>
<member name="P:Performance.EntityModels.ag_bodysource.ManagementAllowance">
<member name="P:Performance.EntityModels.ag_bodysource.WorkPerformance">
<summary>
管理津贴
</summary>
</member>
<member name="P:Performance.EntityModels.ag_bodysource.IndividualReward">
<summary>
单项奖励
</summary>
</member>
<member name="P:Performance.EntityModels.ag_bodysource.AllocationOfKeySpecialty">
<summary>
重点专科分配
工作量绩效
</summary>
</member>
<member name="P:Performance.EntityModels.ag_bodysource.DeptReward">
......@@ -936,12 +926,12 @@
</member>
<member name="P:Performance.EntityModels.ag_headsource.TheTotalAllocationOfPerformanceResults">
<summary>
科室单项奖励
业绩分配绩效总额
</summary>
</member>
<member name="P:Performance.EntityModels.ag_headsource.BasisPerformance">
<member name="P:Performance.EntityModels.ag_headsource.TotalDeptReward">
<summary>
业绩分配绩效总额
科室单项奖励
</summary>
</member>
<member name="P:Performance.EntityModels.ag_headsource.SeniorityTitlesAccountedPerformance">
......
......@@ -99,6 +99,10 @@ public enum DataFormat
普通格式,
/// <summary> 小数 </summary>
小数,
/// <summary> 小数 </summary>
小数1,
/// <summary> 整数 </summary>
整数,
/// <summary> 货币 </summary>
货币,
/// <summary> 百分比 </summary>
......
......@@ -12,12 +12,12 @@ public HandsonTableBase()
{
ColHeaders = new List<string>();
Columns = new List<HandsonColumn>();
Data = new List<Dictionary<string, string>>();
Data = new List<Dictionary<string, object>>();
NestedHeadersArray = new List<List<string>>();
}
public List<string> ColHeaders { get; set; }
public List<Dictionary<string, string>> Data { get; set; }
public List<Dictionary<string, object>> Data { get; set; }
public List<HandsonColumn> Columns { get; set; }
public List<List<string>> NestedHeadersArray { get; set; }
}
......@@ -95,9 +95,9 @@ private void InitColumns(List<collect_permission> permissions)
Columns = columns;
}
private Dictionary<string, string> CreateDataRow(string key, string value)
private Dictionary<string, object> CreateDataRow(string key, string value)
{
var temp = new Dictionary<string, string>() { { key, value } };
var temp = new Dictionary<string, object>() { { key, value } };
foreach (var item in ColHeaders)
{
if (!temp.ContainsKey(item))
......@@ -125,6 +125,16 @@ public HandsonColumn(string data, bool readOnly = false, DataFormat format = Dat
NumericFormat = new NumericFormat { Pattern = "0,00.00" };
break;
case DataFormat.小数1:
Type = "numeric";
NumericFormat = new NumericFormat { Pattern = "0,00.0" };
break;
case DataFormat.整数:
Type = "numeric";
NumericFormat = new NumericFormat { Pattern = "0,00" };
break;
case DataFormat.百分比:
Type = "numeric";
NumericFormat = new NumericFormat { Pattern = "0,00.00%" };
......
......@@ -5,14 +5,6 @@
namespace Performance.DtoModels
{
public class SecondLoadRequest
{
public int SecondId { get; set; }
/// <summary>
/// 计算方式:1 不计算 2 横向计算 3 纵向计算
/// </summary>
public int ComputeMode { get; set; }
}
public class SecondEmployeeRequest
{
public string EmployeeName { get; set; }
......
......@@ -14,5 +14,6 @@ public enum ResponseType
ParameterError = 6,
Disable = 7,
TooManyRequests = 8,
Warning = 9,
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace Performance.DtoModels.Second
{
/// <summary>
/// 二次分配计算方式
/// </summary>
public enum ComputeMode
{
/// <summary>
/// 不计算
/// </summary>
NotCalculate = 1,
/// <summary>
/// 横向计算
/// </summary>
Horizontal = 2,
/// <summary>
/// 纵向计算
/// </summary>
Vertical = 3,
}
/// <summary>
/// 人员带出方式 已保存,上次,字典,测算表
/// </summary>
public enum OverrideMode
{
/// <summary>
/// 初始化(用户保存后的数据)
/// </summary>
Initial = 0,
/// <summary>
/// 上一个二次绩效记录
/// </summary>
PrevSecondAllot = 1,
/// <summary>
/// 人员字典
/// </summary>
EmployeeDict = 2,
}
}
namespace Performance.DtoModels
{
public class SecondColumnDictionary
{
public string Label { get; set; }
public string Key { get; set; }
public bool IsTrue { get; set; }
public int Sort { get; set; }
public SecondColumnDictionary()
{
}
public SecondColumnDictionary(string label, string key, bool isTrue, int sort)
{
Label = label;
Key = key;
IsTrue = isTrue;
Sort = sort;
}
}
}
namespace Performance.DtoModels
{
public class SecondComputeCheckResultDto
{
public SecondComputeCheckResultDto(string level, string personnelNumber, string personnelName, string message)
{
Level = level;
PersonnelNumber = personnelNumber;
PersonnelName = personnelName;
Message = message;
}
public string Level { get; set; }
public string PersonnelNumber { get; set; }
public string PersonnelName { get; set; }
public string Message { get; set; }
}
}
using System.Collections.Generic;
namespace Performance.DtoModels
{
public class SecondComputeDto : SecondLoadDto
{
public Dictionary<string, object> Head { get; set; }
public List<Dictionary<string, object>> Body { get; set; }
}
}
using System.Collections.Generic;
namespace Performance.DtoModels
{
public class SecondDetailDto
{
public object Head { get; set; }
public HandsonTableBase Body { get; set; }
public List<SecondColumnDictionary> Dic { get; set; }
}
}
namespace Performance.DtoModels
{
public class SecondLoadDto
{
public int SecondId { get; set; }
/// <summary>
/// 计算方式:1 不计算 2 横向计算 3 纵向计算
/// </summary>
public int ComputeMode { get; set; }
/// <summary>
/// 数据加载方式:0 保存,1 上次,2 字典,3 测算表
/// </summary>
public int OverrideMode { get; set; }
}
}
using System;
using System.Collections.Generic;
namespace Performance.DtoModels
{
public class SecondWorkLoadDto
{
public SecondWorkLoadDto(string name)
{
Name = name;
Unit_Price = 0m;
Items = new List<string>();
AssessmentScore = $"AssessmentScore_{Name}";
WorkPerformance = $"WorkPerformance_{Name}";
WorkloadScore = $"WorkloadScore_{Name}";
}
public string AssessmentScore { get; set; }
public string WorkPerformance { get; set; }
public string WorkloadScore { get; set; }
public decimal Unit_Price { get; set; }
public List<string> Items { get; set; }
public string Name { get; set; }
public void AddItem(string name)
{
if (!Items.Contains(name))
Items.Add(name);
}
}
}
......@@ -77,19 +77,24 @@ public class ag_bodysource
public Nullable<decimal> TitlePerformance { get; set; }
/// <summary>
/// 管理津贴
/// 工作量绩效
/// </summary>
public Nullable<decimal> ManagementAllowance { get; set; }
public Nullable<decimal> WorkPerformance { get; set; }
/// <summary>
/// 单项奖励
/// </summary>
public Nullable<decimal> IndividualReward { get; set; }
///// <summary>
///// 管理津贴
///// </summary>
//public Nullable<decimal> ManagementAllowance { get; set; }
/// <summary>
/// 重点专科分配
/// </summary>
public Nullable<decimal> AllocationOfKeySpecialty { get; set; }
///// <summary>
///// 单项奖励
///// </summary>
//public Nullable<decimal> IndividualReward { get; set; }
///// <summary>
///// 重点专科分配
///// </summary>
//public Nullable<decimal> AllocationOfKeySpecialty { get; set; }
/// <summary>
/// 科室单项奖励
......
......@@ -52,14 +52,19 @@ public class ag_headsource
public Nullable<decimal> DirectorBasisPerformance { get; set; }
/// <summary>
/// 科室单项奖励
/// 业绩分配绩效总额
/// </summary>
public Nullable<decimal> TheTotalAllocationOfPerformanceResults { get; set; }
/// <summary>
/// 业绩分配绩效总额
/// 科室单项奖励
/// </summary>
public Nullable<decimal> BasisPerformance { get; set; }
public Nullable<decimal> TotalDeptReward { get; set; }
///// <summary>
///// 业绩分配绩效总额
///// </summary>
//public Nullable<decimal> BasisPerformance { get; set; }
/// <summary>
/// 年资职称绩效占比
......
......@@ -18,9 +18,9 @@ public static partial class UtilExtensions
/// <returns></returns>
public static T GetValue<T>(this Dictionary<string, object> keyValues, string key, T defaultValue = default(T))
{
object value;
if (keyValues.TryGetValue(key, out value))
return ConvertHelper.To<T>(value, defaultValue);
var pair = keyValues.FirstOrDefault(w => w.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
if (!default(KeyValuePair<string, object>).Equals(pair))
return ConvertHelper.To<T>(pair.Value, defaultValue);
return defaultValue;
}
......@@ -33,13 +33,29 @@ public static T GetValue<T>(this Dictionary<string, object> keyValues, string ke
/// <returns></returns>
public static T GetValue<T>(this SortedDictionary<string, object> keyValues, string key, T defaultValue = default(T))
{
object value;
if (keyValues.TryGetValue(key, out value))
return ConvertHelper.To<T>(value, defaultValue);
var pair = keyValues.FirstOrDefault(w => w.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
if (!default(KeyValuePair<string, object>).Equals(pair))
return ConvertHelper.To<T>(pair.Value, defaultValue);
return defaultValue;
}
/// <summary>
/// 添加或修改
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="keyValues"></param>
/// <param name="key"></param>
/// <returns></returns>
public static void AddOrUpdate(this Dictionary<string, object> keyValues, string key, object value)
{
var pair = keyValues.FirstOrDefault(w => w.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
if (default(KeyValuePair<string, object>).Equals(pair))
keyValues.Add(key, value);
else
keyValues[key] = value;
}
/// <summary>
/// form 转换 键值对
/// </summary>
/// <param name="pairs"></param>
......
......@@ -26,5 +26,27 @@ public static string[] SplitRemoveEmpty(this string text, params string[] separa
{
return text.Split(separator, StringSplitOptions.RemoveEmptyEntries);
}
/// <summary>
/// 确定此字符串实例的开头是否与指定的匹配 忽略字母的大小写
/// </summary>
/// <param name="text"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool StartsWithIgnoreCase(this string text, string value)
{
return text.StartsWith(value, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// 确定此字符串是否与指定的字符串对象具有相同的值 忽略字母的大小写
/// </summary>
/// <param name="text"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool EqualsIgnoreCase(this string text, string value)
{
return text.Equals(value, StringComparison.OrdinalIgnoreCase);
}
}
}
......@@ -12,7 +12,7 @@
namespace Performance.Repository
{
/// <summary>
/// per_apr_amount Repository
/// per_apr_amount_hide Repository
/// </summary>
public partial class PerforPerapramounthideRepository : PerforRepository<per_apr_amount_hide>
{
......
......@@ -208,7 +208,7 @@ public PageList<per_employee> GetPersons(int allotId, int userId, PersonParamsRe
if (request != null && !string.IsNullOrEmpty(request.SearchQuery))
{
exp = exp.And(t => true && (t.AccountingUnit.Contains(request.SearchQuery) || t.DoctorName.Contains(request.SearchQuery) || t.Department.Contains(request.SearchQuery)));
exp = exp.And(t => true && (t.AccountingUnit.Contains(request.SearchQuery) || t.PersonnelNumber.Contains(request.SearchQuery) || t.DoctorName.Contains(request.SearchQuery) || t.Department.Contains(request.SearchQuery)));
}
var result = new List<per_employee>();
......
......@@ -6,32 +6,75 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Performance.Infrastructure;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Performance.DtoModels.Second;
using Microsoft.Extensions.Logging;
namespace Performance.Services
{
public class RedistributionService : IAutoInjection
{
#region 构造函数
private readonly ILogger<RedistributionService> _logger;
private readonly SecondAllotDetails _secondAllotDetails;
private readonly PerforPerallotRepository _perallotRepository;
private readonly PerforPeremployeeRepository _peremployeeRepository;
private readonly PerforAgsecondallotRepository _secondallotRepository;
private readonly PerforPerapramountRepository _perapramountRepository;
private readonly PerforAgothersourceRepository _agothersourceRepository;
private readonly PerforAgfixatitemRepository _agfixatitemRepository;
private readonly PerforAgheadsourceRepository _agheadsourceRepository;
private readonly PerforAgbodysourceRepository _agbodysourceRepository;
private readonly PerforAgworktypesourceRepository _agworktypesourceRepository;
private readonly PerforAgworkloadRepository _agworkloadRepository;
private readonly PerforAgworkloadsourceRepository _agworkloadsourceRepository;
private readonly PerforImemployeelogisticsRepository _imemployeelogisticsRepository;
public RedistributionService(
ILogger<RedistributionService> logger,
SecondAllotDetails secondAllotDetails,
PerforPerallotRepository perallotRepository,
PerforPeremployeeRepository peremployeeRepository,
PerforAgsecondallotRepository secondallotRepository,
PerforAgworkloadRepository agworkloadRepository)
PerforPerapramountRepository perapramountRepository,
PerforAgothersourceRepository agothersourceRepository,
PerforAgfixatitemRepository agfixatitemRepository,
PerforAgheadsourceRepository agheadsourceRepository,
PerforAgbodysourceRepository agbodysourceRepository,
PerforAgworktypesourceRepository agworktypesourceRepository,
PerforAgworkloadRepository agworkloadRepository,
PerforAgworkloadsourceRepository agworkloadsourceRepository,
PerforImemployeelogisticsRepository imemployeelogisticsRepository)
{
_logger = logger;
_secondAllotDetails = secondAllotDetails;
_perallotRepository = perallotRepository;
_peremployeeRepository = peremployeeRepository;
_secondallotRepository = secondallotRepository;
_perapramountRepository = perapramountRepository;
_agothersourceRepository = agothersourceRepository;
_agfixatitemRepository = agfixatitemRepository;
_agheadsourceRepository = agheadsourceRepository;
_agbodysourceRepository = agbodysourceRepository;
_agworktypesourceRepository = agworktypesourceRepository;
_agworkloadRepository = agworkloadRepository;
_agworkloadsourceRepository = agworkloadsourceRepository;
_imemployeelogisticsRepository = imemployeelogisticsRepository;
}
#endregion
#region 加载
/// <summary>
///
/// 加载
/// </summary>
/// <param name="secondId"></param>
/// <param name="computeMode">计算方式:1 不计算 2 横向计算 3 纵向计算</param>
/// <param name="overrideMode">数据加载方式:0 保存,1 上次,2 字典,3 测算表</param>
/// <returns></returns>
public HandsonTableBase Load(int secondId, int computeMode)
public SecondDetailDto Load(int secondId, ComputeMode computeMode, OverrideMode overrideMode)
{
var second = _secondallotRepository.GetEntity(t => t.Id == secondId);
if (second == null) throw new PerformanceException("参数SecondId无效!");
......@@ -45,17 +88,39 @@ public HandsonTableBase Load(int secondId, int computeMode)
HandsonTableBase handson = new HandsonTableBase();
switch (computeMode)
{
case 1:
case ComputeMode.NotCalculate:
handson = ComputeMode_Format1(colHeaderCustoms, columnCustoms);
break;
case 2:
case ComputeMode.Horizontal:
handson = ComputeMode_Format2(colHeaderCustoms, columnCustoms);
break;
case 3:
case ComputeMode.Vertical:
handson = ComputeMode_Format3(colHeaderCustoms, columnCustoms, loads);
break;
}
// 先占位,更加选择加载指定范围数据
// 加载方式分 保存,上次,字典,测算表
var loadEmployees = LoadEmployees(allot, second, overrideMode);
// 设置固定信息默认值
foreach (var item in loadEmployees)
{
item.StaffCoefficient = item.StaffCoefficient ?? 1; // 人员系数
item.ActualAttendance = item.ActualAttendance ?? DateTime.DaysInMonth(allot.Year, allot.Month); // 出勤
item.TitleCoefficient = item.TitleCoefficient ?? 1; // 职称系数
}
// 加载已保存工作量数据
handson.Data = LoadWorkload(allot, second, loadEmployees);
// 设置工作量考核等分默认值
foreach (var item in handson.Data)
{
foreach (var score in item.Where(w => w.Key.StartsWithIgnoreCase("AssessmentScore_")).ToList())
{
if (score.Value == null)
item.AddOrUpdate(score.Key, 100);
}
}
#region 结构案例
//var colHeaders = new List<string> { "工号", "姓名", "核算单元", "主管", "人员系数", "出勤", "职称", "职称系数", "A班", "P班", "N班", "考核得分", "A班", "P班", "N班", "考核得分", "单项奖励A", "单项奖励B", "夜班绩效", };
......@@ -116,42 +181,475 @@ public HandsonTableBase Load(int secondId, int computeMode)
#endregion
return handson;
var head = LoadHead(computeMode, allot, second);
var dic = GetTableHeaderDictionary(loads);
return new SecondDetailDto { Head = head, Body = handson, Dic = dic };
}
public List<SecondColumnDictionary> GetTableHeaderDictionary(List<TitleValue<string, decimal?>> loads)
{
var maps = new List<SecondColumnDictionary>()
{
new SecondColumnDictionary("人员工号","worknumber",true,100 ),
new SecondColumnDictionary("姓名","name",true,100 ),
new SecondColumnDictionary("核算单元","department",true,100 ),
new SecondColumnDictionary("主管","post",true,100 ),
new SecondColumnDictionary("人员系数","staffcoefficient", true, 200 ),
new SecondColumnDictionary("出勤","actualattendance",true,201 ),
new SecondColumnDictionary("职称","jobtitle",true,202 ),
new SecondColumnDictionary( "职称系数","titlecoefficient", true, 203 ),
new SecondColumnDictionary("职称绩效","titleperformance", true, 299 ),
new SecondColumnDictionary("工作量绩效工资","workperformance", true, 399 ),
new SecondColumnDictionary( "单项奖励","deptreward", true, 499),
new SecondColumnDictionary("可分配绩效","distperformance", true, 500 ),
new SecondColumnDictionary("医院其他绩效","otherperformance", true, 501 ),
new SecondColumnDictionary( "夜班工作量绩效","nightworkperformance", true, 502 ),
new SecondColumnDictionary("预留比例","reservedratio", true, 601 ),
new SecondColumnDictionary("预留金额","reservedamount", true, 602 ),
new SecondColumnDictionary("实发绩效工资金额","realamount", true, 700 ),
};
// 工作量
int sort = 300;
foreach (var item in loads.Where(w => !w.Title.StartsWithIgnoreCase("SingleAwards_")))
{
maps.Add(new SecondColumnDictionary(item.Value, item.Title, false, ++sort));
}
// 单项奖励
sort = 400;
foreach (var item in loads.Where(w => w.Title.StartsWithIgnoreCase("SingleAwards_")))
{
maps.Add(new SecondColumnDictionary(item.Value, item.Title, false, ++sort));
}
return maps.OrderBy(w => w.Sort).ToList();
}
/// <summary>
/// 加载已保存工作量数据,加载时区分:已提交和未提交
/// </summary>
/// <param name="allot"></param>
/// <param name="second"></param>
/// <param name="loadEmployees"></param>
/// <returns></returns>
private List<Dictionary<string, object>> LoadWorkload(per_allot allot, ag_secondallot second, List<ag_bodysource> loadEmployees)
{
List<Dictionary<string, object>> result = new List<Dictionary<string, object>>();
var status = (new int[] { (int)SecondAllotStatus.WaitReview, (int)SecondAllotStatus.PassAudit });
// 已提交
if (second.Status.HasValue && status.Contains(second.Status.Value))
{
var bodyDynamic = _agworkloadsourceRepository.GetEntities(t => loadEmployees.Select(w => w.Id).Contains(t.BodyId));
foreach (var employee in loadEmployees)
{
var dict = JsonHelper.Deserialize<Dictionary<string, object>>(JsonHelper.Serialize(employee));
if (bodyDynamic != null && bodyDynamic.Any(t => t.BodyId == employee.Id))
{
foreach (var col in bodyDynamic.Where(t => t.BodyId == employee.Id))
{
dict.Add(col.ItemId, col.Value);
}
}
result.Add(dict);
}
}
// 未提交
else
{
var bodyDynamic = _agworkloadsourceRepository.GetEntities(t => loadEmployees.Select(w => w.Id).Contains(t.BodyId));
var workloads = _agworkloadRepository.GetEntities(t => t.HospitalId == allot.HospitalId && t.Department == second.Department && t.UnitType == second.UnitType);
if (workloads != null && workloads.Any())
{
foreach (var employee in loadEmployees)
{
var dict = JsonHelper.Deserialize<Dictionary<string, object>>(JsonHelper.Serialize(employee));
foreach (var workitem in workloads)
{
var value = bodyDynamic?.FirstOrDefault(w => w.BodyId == employee.Id && w.WorkloadId == workitem.Id)?.Value;
dict.Add(workitem.ItemId, value);
}
result.Add(dict);
}
}
}
return result;
}
/// <summary>
/// 顶部信息加载
/// </summary>
/// <param name="computeMode"></param>
/// <param name="second"></param>
/// <param name="allot"></param>
/// <returns></returns>
private Dictionary<string, object> LoadHead(ComputeMode computeMode, per_allot allot, ag_secondallot second)
{
var head = new Dictionary<string, object>();
// 公共顶部信息
head.AddOrUpdate(nameof(ag_headsource.SecondId), second.Id);
head.AddOrUpdate(nameof(ag_headsource.PaymentOfTheMonth), $"{allot.Year}{allot.Month.ToString().PadLeft(2, '0')}月");
head.AddOrUpdate(nameof(ag_headsource.TotalDistPerformance), second.RealGiveFee ?? 0);
head.AddOrUpdate(nameof(ag_headsource.NightShiftWorkPerforTotal), second.NightShiftWorkPerforFee ?? 0);
head.AddOrUpdate(nameof(ag_headsource.TotalPerformance), (second.RealGiveFee ?? 0) - (second.NightShiftWorkPerforFee ?? 0));
// 横向 纵向 特有顶部信息
if (computeMode != ComputeMode.NotCalculate)
{
head.AddOrUpdate(nameof(ag_headsource.DaysFullAttendance), DateTime.DaysInMonth(allot.Year, allot.Month));
head.AddOrUpdate(nameof(ag_headsource.SeniorityTitlesAccountedPerformance), 0.2m);
head.AddOrUpdate(nameof(ag_headsource.Workload_Ratio_Default), 0.8m);
var history = _agheadsourceRepository.GetEntity(t => t.SecondId == second.Id);
if (history != null)
{
head.AddOrUpdate(nameof(ag_headsource.SeniorityTitlesAccountedPerformance), history.SeniorityTitlesAccountedPerformance);
head.AddOrUpdate(nameof(ag_headsource.Workload_Ratio_Default), history.Workload_Ratio_Default);
head.AddOrUpdate(nameof(ag_headsource.DaysFullAttendance), history.DaysFullAttendance);
}
// 多工作量加载
var headDynamic = _agworktypesourceRepository.GetEntities(t => t.SecondId == second.Id);
if (headDynamic != null && headDynamic.Any())
{
foreach (var item in headDynamic.Where(w => w.FieldId.StartsWithIgnoreCase("Workload_Ratio_")).OrderBy(t => t.Id))
{
head.AddOrUpdate(item.FieldId, item.Value ?? 0);
}
}
}
return head;
}
/// <summary>
/// 按指定方式加载人员数据
/// </summary>
/// <param name="secondId"></param>
/// <param name="mode"></param>
/// <returns></returns>
private List<ag_bodysource> LoadEmployees(per_allot allot, ag_secondallot second, OverrideMode mode)
{
var employees = _peremployeeRepository.GetEntities(w => w.AllotId == second.AllotId);
// 默认流程
if (mode == OverrideMode.Initial)
{
var saveDatas = _agbodysourceRepository.GetEntities(w => w.SecondId == second.Id);
// 数据带出顺序 1 已保存 2 上次 3 科室字典(或EXCEL行政工勤)
if (saveDatas != null)
return saveDatas;
List<string> numbers = LoadEmployees_PrevSecondAllot(allot, second);
// 如果行政工勤科室没有保存数据,则默认从EXCEL中带出数据
if (UnitTypeUtil.IsOffice(second.UnitType) && (numbers == null || numbers.Count == 0))
numbers = LoadEmployees_OfficeExcel(second);
if (numbers == null || numbers.Count == 0)
numbers = LoadEmployees_EmployeeDict(second, employees);
return LoadEmployeeByDictionary(second, employees, numbers);
}
// 用户指定加载
else
{
List<string> numbers = new List<string>();
if (mode == OverrideMode.PrevSecondAllot)
numbers = LoadEmployees_PrevSecondAllot(allot, second);
// 如果行政工勤科室则默认从EXCEL中带出数据
else if (mode == OverrideMode.EmployeeDict && UnitTypeUtil.IsOffice(second.UnitType))
numbers = LoadEmployees_OfficeExcel(second);
else if (mode == OverrideMode.EmployeeDict)
numbers = LoadEmployees_EmployeeDict(second, employees);
if (numbers == null || numbers.Count == 0)
return new List<ag_bodysource>();
return LoadEmployeeByDictionary(second, employees, numbers);
}
//var data = new List<Dictionary<string, object>>();
//foreach (var item in loadDatas)
//{
// data.Add(new Dictionary<string, object>
// {
// { nameof(ag_bodysource.SecondId), item.SecondId },
// { nameof(ag_bodysource.Department), item.Department },
// { nameof(ag_bodysource.WorkNumber), item.WorkNumber },
// { nameof(ag_bodysource.Name), item.Name },
// { nameof(ag_bodysource.JobTitle), item.JobTitle },
// { nameof(ag_bodysource.ReservedRatio), item.ReservedRatio },
// { nameof(ag_bodysource.Post), item.Post },
// // 设置默认值
// { nameof(ag_bodysource.StaffCoefficient), item.StaffCoefficient ?? 1 },
// { nameof(ag_bodysource.ActualAttendance), item.ActualAttendance ?? DateTime.DaysInMonth(allot.Year, allot.Month) },
// { nameof(ag_bodysource.TitleCoefficient), item.TitleCoefficient ?? 1 },
// });
//}
//return data;
}
List<ag_bodysource> LoadEmployeeByDictionary(ag_secondallot second, List<per_employee> employees, List<string> numbers)
{
List<ag_bodysource> loadDatas = new List<ag_bodysource>();
foreach (var personnelNumber in numbers)
{
var existEmp = employees.FirstOrDefault(w => w.PersonnelNumber?.Trim() == personnelNumber?.Trim());
if (existEmp == null)
continue;
loadDatas.Add(new ag_bodysource
{
SecondId = second.Id,
Department = existEmp.AccountingUnit,
WorkNumber = existEmp.PersonnelNumber,
Name = existEmp.DoctorName,
JobTitle = existEmp.JobTitle,
ReservedRatio = existEmp.ReservedRatio,
Post = "否",
});
}
return loadDatas;
}
private List<string> LoadEmployees_PrevSecondAllot(per_allot allot, ag_secondallot second)
{
//List<ag_bodysource> bodysources = new List<ag_bodysource>();
//// 上次二次分配分三种情况,1.其他来源 2.单工作量 3.多工作量
//var prevSecondAllot = _secondAllotDetails.GetPreviousSecondAllot(allot.HospitalId, second);
//var status = new int[] { (int)SecondAllotStatus.WaitReview, (int)SecondAllotStatus.PassAudit };
//if (prevSecondAllot != null && status.Contains(prevSecondAllot.Status ?? (int)SecondAllotStatus.Uncommitted))
//{
// if (prevSecondAllot.Status == 6)
// {
// var prevDatas = _agothersourceRepository.GetEntities(w => w.SecondId == prevSecondAllot.Id);
// if (prevDatas != null)
// {
// foreach (var pre in prevDatas)
// {
// var existEmp = dicEmployees.FirstOrDefault(w => w.PersonnelNumber?.Trim() == pre.WorkNumber?.Trim());
// if (existEmp != null)
// continue;
// bodysources.Add(new ag_bodysource
// {
// SecondId = second.Id,
// Department = existEmp.AccountingUnit,
// WorkNumber = existEmp.PersonnelNumber,
// Name = existEmp.DoctorName,
// JobTitle = existEmp.JobTitle,
// ReservedRatio = existEmp.ReservedRatio,
// Post = "否",
// });
// }
// }
// }
// else if (prevSecondAllot.Status == 7 || prevSecondAllot.Status == 8)
// {
// var prevDatas = _agfixatitemRepository
// .GetEntities(w => w.SecondId == prevSecondAllot.Id && w.RowNumber.HasValue && w.RowNumber > -1 && w.Type == (int)TempColumnType.TableFixedColumns);
// if (prevDatas != null)
// {
// foreach (var row in prevDatas.GroupBy(w => w.RowNumber.Value))
// {
// var personnelNumber = row.FirstOrDefault(w => w.ItemName == "人员工号")?.ItemValue;
// if (string.IsNullOrEmpty(personnelNumber))
// continue;
// var existEmp = dicEmployees.FirstOrDefault(w => w.PersonnelNumber?.Trim() == personnelNumber?.Trim());
// if (existEmp != null)
// continue;
// bodysources.Add(new ag_bodysource
// {
// SecondId = second.Id,
// Department = existEmp.AccountingUnit,
// WorkNumber = existEmp.PersonnelNumber,
// Name = existEmp.DoctorName,
// JobTitle = existEmp.JobTitle,
// ReservedRatio = existEmp.ReservedRatio,
// Post = "否",
// });
// }
// }
// }
// else if (prevSecondAllot.Status == 9 || prevSecondAllot.Status == 10)
// {
// var prevDatas = _agbodysourceRepository.GetEntities(w => w.SecondId == prevSecondAllot.Id);
// if (prevDatas != null)
// {
// foreach (var pre in prevDatas)
// {
// var existEmp = dicEmployees.FirstOrDefault(w => w.PersonnelNumber?.Trim() == pre.WorkNumber?.Trim());
// if (existEmp != null)
// continue;
// bodysources.Add(new ag_bodysource
// {
// SecondId = second.Id,
// Department = existEmp.AccountingUnit,
// WorkNumber = existEmp.PersonnelNumber,
// Name = existEmp.DoctorName,
// JobTitle = existEmp.JobTitle,
// ReservedRatio = existEmp.ReservedRatio,
// Post = "否",
// });
// }
// }
// }
//}
//return bodysources;
List<string> numbers = new List<string>();
// 上次二次分配分三种情况,1.其他来源 2.单工作量 3.多工作量
var prevSecondAllot = _secondAllotDetails.GetPreviousSecondAllot(allot.HospitalId, second);
var status = new int[] { (int)SecondAllotStatus.WaitReview, (int)SecondAllotStatus.PassAudit };
if (prevSecondAllot != null && status.Contains(prevSecondAllot.Status ?? (int)SecondAllotStatus.Uncommitted))
{
if (prevSecondAllot.Status == 6)
{
var prevDatas = _agothersourceRepository.GetEntities(w => w.SecondId == prevSecondAllot.Id);
numbers = prevDatas
?.Where(pre => string.IsNullOrEmpty(pre.WorkNumber?.Trim()))
.Select(pre => pre.WorkNumber?.Trim())
.Distinct().ToList() ?? new List<string>();
}
else if (prevSecondAllot.Status == 7 || prevSecondAllot.Status == 8)
{
var prevDatas = _agfixatitemRepository
.GetEntities(w => w.SecondId == prevSecondAllot.Id && w.RowNumber.HasValue && w.RowNumber > -1 && w.Type == (int)TempColumnType.TableFixedColumns);
numbers = prevDatas
?.GroupBy(w => w.RowNumber.Value)
.Select(row => row.FirstOrDefault(w => w.ItemName == "人员工号")?.ItemValue)
.Where(w => string.IsNullOrEmpty(w?.Trim()))
.Distinct().ToList() ?? new List<string>();
}
else if (prevSecondAllot.Status == 9 || prevSecondAllot.Status == 10)
{
var prevDatas = _agbodysourceRepository.GetEntities(w => w.SecondId == prevSecondAllot.Id);
numbers = prevDatas
?.Where(pre => string.IsNullOrEmpty(pre.WorkNumber?.Trim()))
.Select(pre => pre.WorkNumber?.Trim())
.Distinct().ToList() ?? new List<string>();
}
}
return numbers;
}
private List<string> LoadEmployees_EmployeeDict(ag_secondallot second, List<per_employee> dicEmployees)
{
//if (dicEmployees == null)
// return new List<ag_bodysource>();
//var employees = dicEmployees
// .Where(w => w.UnitType == second.UnitType && w.AccountingUnit == second.Department)
// .Select(emp => new ag_bodysource
// {
// SecondId = second.Id,
// Department = emp.AccountingUnit,
// WorkNumber = emp.PersonnelNumber,
// Name = emp.DoctorName,
// JobTitle = emp.JobTitle,
// ReservedRatio = emp.ReservedRatio,
// Post = "否",
// }).ToList();
//return employees;
var employees = dicEmployees
?.Where(w => w.UnitType == second.UnitType && w.AccountingUnit == second.Department)
.Select(emp => emp.PersonnelNumber?.Trim())
.Distinct().ToList() ?? new List<string>();
return employees;
}
private List<string> LoadEmployees_OfficeExcel(ag_secondallot second)
{
//List<ag_bodysource> bodysources = new List<ag_bodysource>();
//if (dicEmployees == null)
// return bodysources;
//var employees = _imemployeelogisticsRepository.GetEntities(w => w.AllotID == second.AllotId && w.AccountingUnit == second.Department);
//if (employees != null)
//{
// foreach (var emp in employees)
// {
// var existEmp = dicEmployees.FirstOrDefault(w => w.PersonnelNumber?.Trim() == emp.PersonnelNumber?.Trim());
// if (existEmp != null)
// continue;
// bodysources.Add(new ag_bodysource
// {
// SecondId = second.Id,
// Department = existEmp.AccountingUnit,
// WorkNumber = existEmp.PersonnelNumber,
// Name = existEmp.DoctorName,
// JobTitle = existEmp.JobTitle,
// ReservedRatio = existEmp.ReservedRatio,
// Post = "否",
// });
// }
//}
//return bodysources;
List<string> numbers = new List<string>();
var employees = _imemployeelogisticsRepository.GetEntities(w => w.AllotID == second.AllotId && w.AccountingUnit == second.Department);
if (employees != null)
numbers = employees.Select(w => w.PersonnelNumber).ToList();
return numbers;
}
private List<string> LoadEmployees_Save(List<ag_bodysource> saveDatas)
{
return saveDatas.Select(w => w.WorkNumber).ToList();
}
#region 动态生成列头信息
/// <summary>
/// 动态生成列头信息
/// </summary>
/// <param name="computeMode"></param>
/// <param name="loads"></param>
/// <returns></returns>
private (List<string> colHeaderCustoms, List<HandsonColumn> columnCustoms) GetCustomColumns(int computeMode, List<TitleValue<string, decimal?>> loads)
private (List<string> colHeaderCustoms, List<HandsonColumn> columnCustoms) GetCustomColumns(ComputeMode computeMode, List<TitleValue<string, decimal?>> loads)
{
var colHeaderCustoms = new List<string>();
var columnCustoms = new List<HandsonColumn>();
// 工作量
if (computeMode == 2 || computeMode == 3)
if (computeMode == ComputeMode.Horizontal || computeMode == ComputeMode.Vertical)
{
var keys = loads.Where(w => w.Title.StartsWith("AssessmentScore_")).Select(w => w.Title.Replace("AssessmentScore_", "")).Distinct();
var keys = loads.Where(w => w.Title.StartsWithIgnoreCase("AssessmentScore_")).Select(w => w.Title.Replace("AssessmentScore_", "")).Distinct();
foreach (var key in keys)
{
foreach (var item in loads.Where(w => w.Title.Equals($"AssessmentScore_{key}") || w.Title.StartsWith($"Workload_{key}_")))
if (loads.Any(w => w.Title.StartsWithIgnoreCase($"Workload_{key}_")))
{
colHeaderCustoms.Add(item.Value);
columnCustoms.Add(new HandsonColumn(item.Title, format: DataFormat.小数));
foreach (var item in loads.Where(w => w.Title.EqualsIgnoreCase($"AssessmentScore_{key}") || w.Title.StartsWithIgnoreCase($"Workload_{key}_")))
{
colHeaderCustoms.Add(item.Value);
columnCustoms.Add(new HandsonColumn(item.Title.ToLower(), format: DataFormat.小数));
}
}
}
}
// 单项奖励
foreach (var awards in loads.Where(w => w.Title.StartsWith("SingleAwards_")))
foreach (var awards in loads.Where(w => w.Title.StartsWithIgnoreCase("SingleAwards_")))
{
colHeaderCustoms.Add(awards.Value);
columnCustoms.Add(new HandsonColumn(awards.Title, format: DataFormat.小数));
columnCustoms.Add(new HandsonColumn(awards.Title.ToLower(), format: DataFormat.小数));
}
return (colHeaderCustoms, columnCustoms);
}
#endregion
#region 获取工作量及单项奖励
/// <summary>
/// 获取工作量及单项奖励
/// </summary>
......@@ -159,7 +657,7 @@ public HandsonTableBase Load(int secondId, int computeMode)
/// <param name="unitType"></param>
/// <param name="accountingUnit"></param>
/// <returns></returns>
private List<TitleValue<string, decimal?>> GetWorkLoads(int hospitalId, string unitType, string accountingUnit)
public List<TitleValue<string, decimal?>> GetWorkLoads(int hospitalId, string unitType, string accountingUnit)
{
var workloads = _agworkloadRepository.GetEntities(t => t.HospitalId == hospitalId && t.Department == accountingUnit && t.UnitType == unitType) ?? new List<ag_workload>();
var loads = workloads
......@@ -169,7 +667,9 @@ public HandsonTableBase Load(int secondId, int computeMode)
return loads;
}
#endregion
#region 三种计算对应的格式
/// <summary>
/// 格式生成,不计算,手动录入
/// </summary>
......@@ -179,23 +679,22 @@ public HandsonTableBase Load(int secondId, int computeMode)
private HandsonTableBase ComputeMode_Format1(List<string> colHeaders, List<HandsonColumn> columns)
{
HandsonTableBase handson = new HandsonTableBase();
handson.ColHeaders.AddRange(new string[] { "工号", "姓名", "核算单元", "主管", "职称绩效", "工作量绩效工资", });
handson.ColHeaders.AddRange(new string[] { "工号", "姓名",/* "核算单元",*/ "主管", "职称绩效", "工作量绩效工资", });
handson.Columns.AddRange(
new HandsonColumn[]
{
new HandsonColumn("WorkNumber"),
new HandsonColumn("Name"),
new HandsonColumn("Department"),
new HandsonColumn("Post"),
new HandsonColumn("TitlePerformance", format: DataFormat.小数),
new HandsonColumn("WorkPerformance", format: DataFormat.小数),
new HandsonColumn(nameof(ag_bodysource.WorkNumber).ToLower()),
new HandsonColumn(nameof(ag_bodysource.Name).ToLower()),
//new HandsonColumn(nameof(ag_bodysource.Department).ToLower()),
new HandsonColumn(nameof(ag_bodysource.TitlePerformance).ToLower(), format: DataFormat.小数),
new HandsonColumn(nameof(ag_bodysource.WorkPerformance).ToLower(), format: DataFormat.小数),
});
handson.ColHeaders.AddRange(colHeaders);
handson.Columns.AddRange(columns);
handson.ColHeaders.AddRange(new string[] { "夜班绩效", });
handson.Columns.AddRange(new HandsonColumn[] { new HandsonColumn("NightWorkPerformance", format: DataFormat.小数), });
handson.Columns.AddRange(new HandsonColumn[] { new HandsonColumn(nameof(ag_bodysource.NightWorkPerformance).ToLower(), format: DataFormat.小数), });
return handson;
}
......@@ -208,25 +707,25 @@ private HandsonTableBase ComputeMode_Format1(List<string> colHeaders, List<Hands
private HandsonTableBase ComputeMode_Format2(List<string> colHeaders, List<HandsonColumn> columns)
{
HandsonTableBase handson = new HandsonTableBase();
handson.ColHeaders.AddRange(new string[] { "工号", "姓名", "核算单元", "主管", "人员系数", "出勤", "职称", "职称系数", });
handson.ColHeaders.AddRange(new string[] { "工号", "姓名", /*"核算单元",*/ "主管", "人员系数", "出勤", "职称", "职称系数", });
handson.Columns.AddRange(
new HandsonColumn[]
{
new HandsonColumn("WorkNumber"),
new HandsonColumn("Name"),
new HandsonColumn("Department"),
new HandsonColumn("Post"),
new HandsonColumn("StaffCoefficient", format: DataFormat.小数),
new HandsonColumn("ActualAttendance", format: DataFormat.小数),
new HandsonColumn("JobTitle"),
new HandsonColumn("TitleCoefficient", format: DataFormat.小数),
new HandsonColumn(nameof(ag_bodysource.WorkNumber).ToLower()),
new HandsonColumn(nameof(ag_bodysource.Name).ToLower()),
//new HandsonColumn(nameof(ag_bodysource.Department).ToLower()),
new HandsonColumn(nameof(ag_bodysource.Post).ToLower()){ Type = "autocomplete", Strict = true, Source = new string[] { "是", "否"} },
new HandsonColumn(nameof(ag_bodysource.StaffCoefficient).ToLower(), format: DataFormat.小数),
new HandsonColumn(nameof(ag_bodysource.ActualAttendance).ToLower(), format: DataFormat.小数1),
new HandsonColumn(nameof(ag_bodysource.JobTitle).ToLower()),
new HandsonColumn(nameof(ag_bodysource.TitleCoefficient).ToLower(), format: DataFormat.小数),
});
handson.ColHeaders.AddRange(colHeaders);
handson.Columns.AddRange(columns);
handson.ColHeaders.AddRange(new string[] { "夜班绩效", });
handson.Columns.AddRange(new HandsonColumn[] { new HandsonColumn("NightWorkPerformance", format: DataFormat.小数), });
handson.Columns.AddRange(new HandsonColumn[] { new HandsonColumn(nameof(ag_bodysource.NightWorkPerformance).ToLower(), format: DataFormat.小数), });
return handson;
}
......@@ -244,9 +743,8 @@ private HandsonTableBase ComputeMode_Format3(List<string> colHeaders, List<Hands
var fs = handson.Columns.Select(col =>
{
var f = loads.FirstOrDefault(w => w.Title.StartsWith($"Workload_") && w.State.HasValue && w.State != 0 && w.Title == col.Data);
return f == null || !f.State.HasValue ? "" : f.State.Value.ToString("F0");
var f = loads.FirstOrDefault(w => w.Title.StartsWithIgnoreCase($"Workload_") && w.Title.EqualsIgnoreCase(col.Data));
return f == null ? "" : (f.State ?? 0).ToString("F0");
});
handson.NestedHeadersArray.Add(handson.ColHeaders);
......@@ -254,5 +752,556 @@ private HandsonTableBase ComputeMode_Format3(List<string> colHeaders, List<Hands
return handson;
}
#endregion
#endregion
#region 补充医院其他绩效
/// <summary>
/// 补充医院其他绩效
/// </summary>
/// <param name="second"></param>
/// <param name="rows"></param>
public void SupplementOtherPerfor(ag_secondallot second, List<Dictionary<string, object>> rows)
{
if (rows == null || rows.Count == 0)
return;
var perapramounts = _perapramountRepository
.GetFullAmount(t => t.AllotId == second.AllotId && t.Status == 3);
if (perapramounts == null || !perapramounts.Any())
return;
foreach (var row in rows)
{
var personnelNumber = row.GetValue(nameof(ag_bodysource.WorkNumber), "");
var amounts = perapramounts.Where(w => w.PersonnelNumber?.Trim() == personnelNumber?.Trim());
row.AddOrUpdate(nameof(ag_bodysource.OtherPerformance), amounts.Sum(w => w.Amount ?? 0));
}
// 补充字典中该科室不存在,但有其它绩效的人员信息
var groupDatas = perapramounts
.Where(t => t.UnitType == second.UnitType && t.AccountingUnit == second.Department)
.GroupBy(w => new { PersonnelNumber = w.PersonnelNumber, DoctorName = w.DoctorName, AccountingUnit = w.AccountingUnit, UnitType = w.UnitType, });
foreach (var item in groupDatas)
{
if (!rows.Any(row => row.GetValue(nameof(ag_bodysource.WorkNumber), "") == item.Key.PersonnelNumber))
{
rows.Add(new Dictionary<string, object>
{
{ nameof(ag_bodysource.SecondId), second.Id },
{ nameof(ag_bodysource.WorkNumber), item.Key.PersonnelNumber },
{ nameof(ag_bodysource.Name), item.Key.DoctorName },
{ nameof(ag_bodysource.Department), item.Key.AccountingUnit },
{ nameof(ag_bodysource.OtherPerformance), item.Sum(w => w.Amount )},
});
}
}
}
#endregion
#region 重算顶部医院其他绩效
/// <summary>
/// 计算顶部相关总和>>医院其他绩效(比较特殊,仅用作展示,所以需要重新计算一次)
/// </summary>
/// <param name="head"></param>
/// <param name="rows"></param>
public void OverviewCalculate_OtherPerformance(Dictionary<string, object> head, List<Dictionary<string, object>> rows)
{
//医院其他绩效总和
var otherPerformance = rows.Sum(row => GetDecimal2(row, nameof(ag_bodysource.OtherPerformance)));
head.AddOrUpdate(nameof(ag_headsource.HosOtherPerformance), otherPerformance);
}
#endregion
#region 计算
/// <summary>
/// 分配结果结果计算
/// </summary>
/// <param name="computeMode"></param>
/// <param name="head"></param>
/// <param name="rows"></param>
/// <param name="loads"></param>
/// <param name="workloadGroups"></param>
public void ResultCompute(ComputeMode computeMode, Dictionary<string, object> head, List<Dictionary<string, object>> rows, List<TitleValue<string, decimal?>> loads, List<SecondWorkLoadDto> workloadGroups)
{
var specialPostName = new string[] { "科主任/护士长", "主任", "主管", "是", };
if (computeMode == ComputeMode.NotCalculate)
{
// 清空无效数据
clearPerformanceWorkload(rows, workloadGroups);
// 行内可分配绩效
distPerformanceCalculate(head, rows, workloadGroups);
// 行内实发绩效
realAmountCalculate(head, rows, specialPostName);
}
else if (computeMode == ComputeMode.Horizontal || computeMode == ComputeMode.Vertical)
{
// 行内计算单项奖励
deptRewardCalculate(rows);
// 计算顶部相关总和
overviewCalculate(head, rows);
// 计算顶部工作量
topWorkloadCalculate(head, workloadGroups);
// 计算顶部年资系数
topSeniorityCalculate(head);
// 行内主任基础绩效
basisPerformanceCalculate(head, rows, specialPostName);
// 行内职称绩效计算
titleCoefficientCalculate(head, rows, specialPostName);
// 行内工作量分组计算
workloadCalculate(head, rows, computeMode, loads, workloadGroups, specialPostName);
// 行内可分配绩效
distPerformanceCalculate(head, rows, workloadGroups);
// 差额从主任或第一个人身上扣除
balanceTotalDistPerformance(head, rows, specialPostName);
// 行内实发绩效
realAmountCalculate(head, rows, specialPostName);
}
}
/// <summary>
/// ComputeMode.NotCalculate 不计算时,清空无效数据
/// </summary>
/// <param name="rows"></param>
/// <param name="workloadGroups"></param>
private void clearPerformanceWorkload(List<Dictionary<string, object>> rows, List<SecondWorkLoadDto> workloadGroups)
{
foreach (var row in rows)
{
foreach (var workload in workloadGroups)
{
row.Remove(workload.WorkloadScore);
row.Remove(workload.AssessmentScore);
row.Remove(workload.WorkPerformance);
foreach (var item in workload.Items)
{
row.Remove(item);
}
}
}
}
/// <summary>
/// 行内计算单项奖励
/// </summary>
/// <param name="rows"></param>
private void deptRewardCalculate(List<Dictionary<string, object>> rows)
{
foreach (var row in rows)
{
decimal total_deptReward = row.Where(w => w.Key.StartsWithIgnoreCase("SingleAwards_")).Sum(r => GetDecimal2(row, r.Key));
row.AddOrUpdate(nameof(ag_bodysource.DeptReward), total_deptReward);
}
}
/// <summary>
/// 计算顶部工作量
/// </summary>
/// <param name="head"></param>
/// <param name="workloadGroups"></param>
private void topWorkloadCalculate(Dictionary<string, object> head, List<SecondWorkLoadDto> workloadGroups)
{
foreach (var workload in workloadGroups)
{
var amount = GetDecimal2(head, nameof(ag_headsource.TheTotalAllocationOfPerformanceResults)) * GetDecimal2(head, $"Workload_Ratio_{workload.Name}");
head.AddOrUpdate($"Workload_Amount_{workload.Name}", amount);
}
}
/// <summary>
/// 计算顶部年资系数
/// </summary>
/// <param name="head"></param>
private void topSeniorityCalculate(Dictionary<string, object> head)
{
var amount = GetDecimal2(head, nameof(ag_headsource.SeniorityTitlesAccountedPerformance)) * GetDecimal2(head, nameof(ag_headsource.TheTotalAllocationOfPerformanceResults));
head.AddOrUpdate(nameof(ag_headsource.SeniorityTitlesPerformance), amount);
}
/// <summary>
/// 计算顶部相关总和
/// </summary>
/// <param name="head"></param>
/// <param name="rows"></param>
private void overviewCalculate(Dictionary<string, object> head, List<Dictionary<string, object>> rows)
{
// 可分配绩效(顶栏) = 科室总绩效 - 夜班绩效(顶栏)
var totalPerformance = GetDecimal2(head, nameof(ag_headsource.TotalDistPerformance)) - GetDecimal2(head, nameof(ag_headsource.NightShiftWorkPerforTotal));
head.AddOrUpdate(nameof(ag_headsource.TotalPerformance), totalPerformance);
//夜班工作量绩效总和
var nightShiftWorkPerforTotal = rows.Sum(row => GetDecimal2(row, nameof(ag_bodysource.NightWorkPerformance)));
head.AddOrUpdate(nameof(ag_headsource.NightShiftWorkPerforTotal), nightShiftWorkPerforTotal);
////医院其他绩效总和
//var otherPerformance = rows.Sum(row => GetDecimal2(row, nameof(ag_bodysource.OtherPerformance)));
//head.AddOrUpdate(nameof(ag_headsource.HosOtherPerformance), otherPerformance);
//科室核算人数 = 人员系数 * 实际出勤
var daysFullAttendance = GetDecimal2(head, nameof(ag_headsource.DaysFullAttendance));
var theNumberOfAccountingDepartment = daysFullAttendance == 0 ? 0m : rows.Sum(row => GetDecimal2(row, nameof(ag_bodysource.StaffCoefficient)) * GetDecimal2(row, nameof(ag_bodysource.ActualAttendance)) / daysFullAttendance);
head.AddOrUpdate(nameof(ag_headsource.TheNumberOfAccountingDepartment), 0m);
// 科室人均 = 可分配绩效 / 科室核算人数
var departmentsPerCapita = theNumberOfAccountingDepartment == 0 ? 0m : GetDecimal2(totalPerformance / theNumberOfAccountingDepartment);
head.AddOrUpdate(nameof(ag_headsource.DepartmentsPerCapita), departmentsPerCapita);
// 科室单项奖励
var totalDeptReward = rows.Sum(row => GetDecimal2(row, nameof(ag_bodysource.DeptReward)));
head.AddOrUpdate(nameof(ag_headsource.TotalDeptReward), totalDeptReward);
// 主任基础绩效(顶部) = 行内主任基础绩效总和
var directorBasisPerformance = rows.Sum(row => GetDecimal2(row, nameof(ag_bodysource.BasisPerformance)));
head.AddOrUpdate(nameof(ag_headsource.DirectorBasisPerformance), directorBasisPerformance);
// 业绩分配绩效总额 = 可分配绩效 - 科主任或护士长基础绩效 - 科室单项奖励
var theTotalAllocationOfPerformanceResults = totalPerformance - directorBasisPerformance - totalDeptReward;
head.AddOrUpdate(nameof(ag_headsource.TheTotalAllocationOfPerformanceResults), theTotalAllocationOfPerformanceResults);
}
/// <summary>
/// 行内主任基础绩效
/// </summary>
/// <param name="head"></param>
/// <param name="rows"></param>
/// <param name="specialPostName"></param>
private void basisPerformanceCalculate(Dictionary<string, object> head, List<Dictionary<string, object>> rows, string[] specialPostName)
{
foreach (var row in rows)
{
// 除 科主任/护士长 以外人员没有 主任基础绩效
// 当前行主任基础绩效 = 科室人均 * 当前行人员系数 * 当前行人员出勤/满勤天数
var post = row.GetValue(nameof(ag_bodysource.Post), "");
if (specialPostName.Contains(post))
{
var daysFullAttendance = GetDecimal2(head, nameof(ag_headsource.DaysFullAttendance));
var departmentsPerCapita = GetDecimal2(head, nameof(ag_headsource.DepartmentsPerCapita));
var staffCoefficient = GetDecimal2(row, nameof(ag_bodysource.StaffCoefficient));
var actualAttendance = GetDecimal2(row, nameof(ag_bodysource.ActualAttendance));
var basisPerformance = daysFullAttendance == 0 ? 0 : departmentsPerCapita * staffCoefficient * actualAttendance / daysFullAttendance;
row.AddOrUpdate(nameof(ag_bodysource.BasisPerformance), basisPerformance);
}
else
{
row.AddOrUpdate(nameof(ag_bodysource.BasisPerformance), 0m);
}
}
}
/// <summary>
/// 行内职称绩效计算
/// </summary>
/// <param name="head"></param>
/// <param name="rows"></param>
/// <param name="specialPostName"></param>
private void titleCoefficientCalculate(Dictionary<string, object> head, List<Dictionary<string, object>> rows, string[] specialPostName)
{
var total_titleCoefficient = 0m;
foreach (var row in rows)
{
var post = row.GetValue(nameof(ag_bodysource.Post), "");
if (!specialPostName.Contains(post))
total_titleCoefficient += GetDecimal2(row, nameof(ag_bodysource.ActualAttendance)) * GetDecimal2(row, nameof(ag_bodysource.TitleCoefficient));
}
var seniorityTitlesPerformance = GetDecimal2(head, nameof(ag_headsource.SeniorityTitlesPerformance));
foreach (var row in rows)
{
var post = row.GetValue(nameof(ag_bodysource.Post), "");
// 科主任/护士长 不参与职称绩效考核
if (specialPostName.Contains(post))
row.AddOrUpdate(nameof(ag_bodysource.TitleCoefficient), 0m);
//个人职称绩效 = ( 当前行实际出勤 * 当前行职称系数 ) / 职称系数总和* 年资职称绩效总和
var titlePerformance = total_titleCoefficient == 0 ? 0 : GetDecimal2(row, nameof(ag_bodysource.ActualAttendance)) * GetDecimal2(row, nameof(ag_bodysource.TitleCoefficient)) / total_titleCoefficient * seniorityTitlesPerformance;
row.AddOrUpdate(nameof(ag_bodysource.TitlePerformance), GetDecimal2(titlePerformance));
}
}
/// <summary>
/// 行内工作量分组计算
/// </summary>
/// <param name="head"></param>
/// <param name="rows"></param>
/// <param name="computeMode"></param>
/// <param name="loads"></param>
/// <param name="workloadGroups"></param>
/// <param name="specialPostName"></param>
private void workloadCalculate(Dictionary<string, object> head, List<Dictionary<string, object>> rows, ComputeMode computeMode,
List<TitleValue<string, decimal?>> loads, List<SecondWorkLoadDto> workloadGroups, string[] specialPostName)
{
// 计算方式:1 不计算 2 横向计算 3 纵向计算
foreach (var row in rows)
{
foreach (var gp in workloadGroups)
{
var workload_score = 0m;
// 计算方式:1 不计算 2 横向计算 3 纵向计算
switch (computeMode)
{
case ComputeMode.Horizontal:
workload_score = ComputeMode_2(row, gp, specialPostName);
break;
case ComputeMode.Vertical:
workload_score = ComputeMode_3(row, loads, gp, specialPostName);
break;
}
// 工作量得分
row.AddOrUpdate(gp.WorkloadScore, GetDecimal2(workload_score));
}
}
// 工作量每分价格计算
foreach (var gp in workloadGroups)
{
// 汇总行内工作量总得分
var total_score = rows.Sum(row => GetDecimal2(row, gp.WorkloadScore) * GetDecimal2(row, gp.AssessmentScore));
// 计算每分价格
gp.Unit_Price = total_score == 0 ? 0 : head.GetValue($"Workload_Amount_{gp.Name}", 0m) / total_score;
}
// 行内工作量绩效计算
foreach (var row in rows)
{
var workPerformance = 0m;
var post = row.GetValue(nameof(ag_bodysource.Post), "");
foreach (var gp in workloadGroups)
{
// 科主任/护士长 不参与工作量考核
if (specialPostName.Contains(post))
{
row.AddOrUpdate(gp.WorkloadScore, 0m);
row.AddOrUpdate(gp.AssessmentScore, 0m);
}
// 工作量绩效 = 工作量得分 * 每分价格 * 考核得分
var workload_fee = GetDecimal2(row.GetValue(gp.WorkloadScore, 0m) * gp.Unit_Price * row.GetValue(gp.AssessmentScore, 0m));
row.AddOrUpdate(gp.WorkPerformance, workload_fee);
workPerformance += workload_fee;
}
// 行内工作量汇总到一起
row.AddOrUpdate(nameof(ag_bodysource.WorkPerformance), workPerformance);
}
}
#region 行内工作量 辅助计算
/// <summary>
/// 获取系数
/// </summary>
/// <param name="workloads"></param>
/// <param name="item"></param>
/// <returns></returns>
decimal getFactorValue(List<TitleValue<string, decimal?>> workloads, string item) => workloads.FirstOrDefault((w) => w.Title == item)?.State ?? 0m;
/// <summary>
/// 3 纵向计算
/// </summary>
/// <param name="row"></param>
/// <param name="loads"></param>
/// <param name="gp"></param>
/// <param name="specialPostName"></param>
/// <returns></returns>
decimal ComputeMode_3(Dictionary<string, object> row, List<TitleValue<string, decimal?>> loads, SecondWorkLoadDto gp, string[] specialPostName)
{
var post = row.GetValue(nameof(ag_bodysource.Post), "");
var workload_score = gp.Items.Sum((item) =>
{
// 科主任/护士长 不参与工作量考核
if (specialPostName.Contains(post))
row.AddOrUpdate(item, 0);
return GetDecimal2(row.GetValue(item, 0m) * getFactorValue(loads, item));
});
return workload_score;
}
/// <summary>
/// 2 横向计算
/// </summary>
/// <param name="row"></param>
/// <param name="gp"></param>
/// <param name="specialPostName"></param>
/// <returns></returns>
decimal ComputeMode_2(Dictionary<string, object> row, SecondWorkLoadDto gp, string[] specialPostName)
{
var post = row.GetValue(nameof(ag_bodysource.Post), "");
var workload_score = 0m;
if (gp.Items.Count % 2 == 0)
{
for (int i = 0; i < gp.Items.Count / 2; i = i + 2)
{
// 科主任/护士长 不参与工作量考核
if (specialPostName.Contains(post))
{
row.AddOrUpdate(gp.Items[i], 0m);
row.AddOrUpdate(gp.Items[i + 1], 0m);
}
var amount = row.GetValue(gp.Items[i], 0m) * row.GetValue(gp.Items[i + 1], 0m);
workload_score += GetDecimal2(amount);
}
}
return workload_score;
}
#endregion
/// <summary>
/// 行内可分配绩效
/// </summary>
/// <param name="head"></param>
/// <param name="rows"></param>
/// <param name="workloadGroups"></param>
private void distPerformanceCalculate(Dictionary<string, object> head, List<Dictionary<string, object>> rows, List<SecondWorkLoadDto> workloadGroups)
{
foreach (var row in rows)
{
var workPerformance = GetDecimal2(row, nameof(ag_bodysource.WorkPerformance));
var titlePerformance = GetDecimal2(row, nameof(ag_bodysource.TitlePerformance));
var deptReward = GetDecimal2(row, nameof(ag_bodysource.DeptReward));
var basisPerformance = GetDecimal2(row, nameof(ag_bodysource.BasisPerformance));
// 可分配绩效 =   当前行职称绩效 + 工作量绩效工资 + 当前行单项奖励 + 当前行主任基础绩效 (科主任护士长)
var distPerformance = titlePerformance + workPerformance + deptReward + basisPerformance;
row.AddOrUpdate(nameof(ag_bodysource.DistPerformance), distPerformance);
}
}
/// <summary>
/// 差额从主任或第一个人身上扣除(小于等于1元)
/// </summary>
/// <param name="head"></param>
/// <param name="rows"></param>
/// <param name="specialPostName"></param>
private void balanceTotalDistPerformance(Dictionary<string, object> head, List<Dictionary<string, object>> rows, string[] specialPostName)
{
var totalPerformance = GetDecimal2(head, nameof(ag_headsource.TotalPerformance));
var total_distPerformance = rows.Sum(row => GetDecimal2(row, nameof(ag_bodysource.DistPerformance)));
var difference = total_distPerformance - totalPerformance;
if (Math.Abs(difference) <= 1)
{
var atRow = rows.Where(row => specialPostName.Contains(row.GetValue(nameof(ag_bodysource.Post), "")));
if (atRow == null || atRow.Count() == 0)
atRow = rows;
if (atRow != null && atRow.Count() > 0)
{
var distPerformance = GetDecimal2(atRow.ElementAt(0), nameof(ag_bodysource.DistPerformance));
atRow.ElementAt(0).AddOrUpdate(nameof(ag_bodysource.DistPerformance), distPerformance - difference);
}
}
}
/// <summary>
/// 行内实发绩效
/// </summary>
/// <param name="head"></param>
/// <param name="rows"></param>
/// <param name="specialPostName"></param>
private void realAmountCalculate(Dictionary<string, object> head, List<Dictionary<string, object>> rows, string[] specialPostName)
{
foreach (var row in rows)
{
// 总绩效 = 夜班工作量绩效 + 医院其他绩效
var row_ShifaAmountOfPerformancePay = GetDecimal2(row, nameof(ag_bodysource.NightWorkPerformance)) + GetDecimal2(row, nameof(ag_bodysource.OtherPerformance));
// ReservedAmount 年度考核发放金额 DistPerformance 可分配绩效
var reservedAmount = GetDecimal2(row, nameof(ag_bodysource.DistPerformance)) * GetDecimal2(row, nameof(ag_bodysource.ReservedRatio));
row.AddOrUpdate(nameof(ag_bodysource.ReservedAmount), reservedAmount);
var realAmount = GetDecimal2(row, nameof(ag_bodysource.DistPerformance)) - GetDecimal2(row, nameof(ag_bodysource.ReservedAmount)) + row_ShifaAmountOfPerformancePay;
row.AddOrUpdate(nameof(ag_bodysource.RealAmount), realAmount);
}
}
#region 四射五入 辅助方式
/// <summary>
/// 从键值对中获取decimal,默认:0,保留2位小数
/// </summary>
/// <param name="pairs"></param>
/// <param name="key"></param>
/// <returns></returns>
private decimal GetDecimal2(Dictionary<string, object> pairs, string key) => GetDecimal2(pairs.GetValue(key, 0m));
/// <summary>
/// decimal?类型转换decimal 默认:0,保留2位小数
/// </summary>
/// <param name="pairs"></param>
/// <param name="key"></param>
/// <returns></returns>
private decimal GetDecimal2(decimal? value) => value.HasValue ? Math.Round(value.Value, 2, MidpointRounding.AwayFromZero) : 0m;
#endregion
#endregion
#region 获取行内工作量分组数
/// <summary>
/// 获取行内工作量分组数
/// </summary>
/// <param name="loads"></param>
/// <returns></returns>
public List<SecondWorkLoadDto> GetTopWorkloadBodyGroups(List<TitleValue<string, decimal?>> loads)
{
List<SecondWorkLoadDto> result = new List<SecondWorkLoadDto>();
if (loads != null)
{
var keys = loads
.Where(w => w.Title.StartsWithIgnoreCase("AssessmentScore_"))
.Select(w => w.Title.Replace("AssessmentScore_", ""))
.Distinct();
foreach (var key in keys)
{
SecondWorkLoadDto dto = new SecondWorkLoadDto(key);
foreach (var item in loads.Where(w => w.Title.StartsWithIgnoreCase($"Workload_{key}_")))
{
dto.AddItem(item.Title);
}
result.Add(dto);
}
}
return result;
}
#endregion
#region 检查工号和姓名是否匹配
/// <summary>
/// 检查工号和姓名是否匹配
/// </summary>
/// <param name="second"></param>
/// <param name="body"></param>
/// <returns></returns>
public List<SecondComputeCheckResultDto> CheckData(ag_secondallot second, List<Dictionary<string, object>> body)
{
if (body == null || body.Count == 0)
throw new PerformanceException("分配人员信息不存在!");
List<SecondComputeCheckResultDto> result = new List<SecondComputeCheckResultDto>();
var employees = _peremployeeRepository.GetEntities(w => w.AllotId == second.AllotId)
.Select(w => new { w.PersonnelNumber, w.DoctorName, w.AccountingUnit, w.UnitType, w.ReservedRatio });
for (int i = 0; i < body.Count; i++)
{
var item = body[i];
if (item.Where(w => w.Value != null && !string.IsNullOrEmpty(w.Value.ToString())).Count() > 0)
{
var number = item.GetValue(nameof(ag_bodysource.WorkNumber), "");
var name = item.GetValue(nameof(ag_bodysource.Name), "");
if (string.IsNullOrEmpty(number) || string.IsNullOrEmpty(name))
{
item.AddOrUpdate(nameof(ResponseType), ResponseType.Warning);
result.Add(new SecondComputeCheckResultDto(nameof(ResponseType.Warning), number, name, $"第{(i + 1)}行,工号或姓名无效;计算式忽略。"));
}
var emp = employees.FirstOrDefault(w => w.PersonnelNumber == number && w.DoctorName == name);
if (emp == null)
{
item.AddOrUpdate(nameof(ResponseType), ResponseType.Error);
result.Add(new SecondComputeCheckResultDto(nameof(ResponseType.Error), number, name, $"第{(i + 1)}行,工号和姓名在字典中不存在,请修复。"));
}
else
{
item.AddOrUpdate(nameof(ResponseType), ResponseType.OK);
item.AddOrUpdate(nameof(ag_bodysource.Department), emp.AccountingUnit);
item.AddOrUpdate(nameof(ag_bodysource.ReservedRatio), emp.ReservedRatio);
}
}
}
return result;
}
#endregion
}
}
......@@ -923,7 +923,7 @@ private void SupplementSecondDetail(ag_secondallot second, List<per_employee> em
/// <param name="hospitalId"></param>
/// <param name="secondAllot"></param>
/// <returns></returns>
private ag_secondallot GetPreviousSecondAllot(int hospitalId, ag_secondallot secondAllot)
public ag_secondallot GetPreviousSecondAllot(int hospitalId, ag_secondallot secondAllot)
{
// 历史删除绩效时,未删除对应的二次绩效记录
var allotList = perallotRepository.GetEntities(w => w.HospitalId == hospitalId)?.OrderBy(s => s.Year).ThenBy(s => s.Month).ToList();
......
......@@ -1605,7 +1605,7 @@ bool VerifySubmissioAmount(decimal? submitDataAmount, decimal? realGiveFee)
if (!VerifySubmissioAmount(total, second.RealGiveFee))
throw new PerformanceException($"总金额与考核后金额不一致!可分配金额:{second.RealGiveFee},提交金额:{total}");
}
else if (new int[] { 9, 10 }.Contains(temp.UseTempId.Value))
else /*if (new int[] { 9, 10 }.Contains(temp.UseTempId.Value))*/
{
var data = agbodysourceRepository.GetEntities(t => t.SecondId == second.Id);
if (data == null || !data.Any())
......@@ -1803,7 +1803,7 @@ public bool NursingDeptAudit(int userId, SecondAuditRequest request)
/// </summary>
/// <param name="secondId">二次绩效Id</param>
/// <returns></returns>
public ag_secondallot GetSecondallot(int secondId)
public ag_secondallot GetSecondAllot(int secondId)
{
return agsecondallotRepository.GetEntity(t => t.Id == secondId);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment