PayrollComputation.cs 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162
  1. using Google.Protobuf.WellKnownTypes;
  2. using NPOI.HPSF;
  3. using NPOI.OpenXmlFormats.Dml.Diagram;
  4. using NPOI.OpenXmlFormats.Spreadsheet;
  5. using NPOI.SS.Formula.Functions;
  6. using NPOI.Util;
  7. using OASystem.API.OAMethodLib.QiYeWeChatAPI;
  8. using OASystem.Domain;
  9. using OASystem.Domain.Entities.PersonnelModule;
  10. using OASystem.Domain.ViewModels.PersonnelModule;
  11. using OASystem.Domain.ViewModels.QiYeWeChat;
  12. using OASystem.Infrastructure.Repositories.Groups;
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Diagnostics.Eventing.Reader;
  16. using System.Linq.Expressions;
  17. using TencentCloud.Ocr.V20181119.Models;
  18. namespace OASystem.API.OAMethodLib
  19. {
  20. /// <summary>
  21. /// 工资计算
  22. /// </summary>
  23. public static class PayrollComputation
  24. {
  25. private static Result _result = new Result();
  26. private static readonly IQiYeWeChatApiService _qiYeWeChatApiService = AutofacIocManager.Instance.GetService<IQiYeWeChatApiService>();
  27. private static readonly UsersRepository _usersRep = AutofacIocManager.Instance.GetService<UsersRepository>();
  28. private static readonly IMapper _mapper = AutofacIocManager.Instance.GetService<IMapper>();
  29. private static readonly decimal _chengDuMinimumWage = 2100.00M;
  30. /// <summary>
  31. /// 计算工资
  32. /// </summary>
  33. /// <param name="pm_WageSheetDattaSources"></param>
  34. /// <param name="userNames"></param>
  35. /// <param name="thisYearMonth"></param>
  36. /// <param name="startDt"></param>
  37. /// <param name="endDt"></param>
  38. /// <returns></returns>
  39. public static async Task<Result> SalaryCalculatorAsync(
  40. List<Pm_WageSheet> pm_WageSheetDattaSources, List<UserNameView> userNames, int userId, string thisYearMonth, DateTime startDt, DateTime endDt)
  41. {
  42. if (pm_WageSheetDattaSources.Count <= 0)
  43. {
  44. _result.Msg = "计算工资传入数据为空!";
  45. return _result;
  46. }
  47. if (userNames.Count <= 0)
  48. {
  49. var nameData = await _usersRep.GetUserNameList(1);
  50. userNames = nameData.Data;
  51. }
  52. //计算时间段内工作日
  53. int work_days = await GetWorkDays(thisYearMonth);
  54. if (work_days <=0)
  55. {
  56. _result.Msg = thisYearMonth+" 工作日未设置,请前往《工作日管理页面》设置!";
  57. return _result;
  58. }
  59. UserIdListView userIdListView = await _qiYeWeChatApiService.GetUserIdListAsync();
  60. if (userIdListView.errcode != 0)
  61. {
  62. _result.Msg = "【企业微信】【打卡】【获取员工ID】【Msg】" + userIdListView.errmsg;
  63. return _result;
  64. }
  65. List<string> qyWhchatIdList = new List<string>();
  66. qyWhchatIdList = userIdListView.dept_user.Select(it => it.userid).ToList();
  67. CheckInDayDataView checkInDayDataView = await _qiYeWeChatApiService.GetCheckInDayDataAsync(qyWhchatIdList, startDt, endDt);
  68. if (checkInDayDataView.errcode != 0)
  69. {
  70. _result.Msg = "【企业微信】【打卡】【获取时间段内所有日打卡】【Msg】" + checkInDayDataView.errmsg;
  71. return _result;
  72. }
  73. //获取所有打卡记录 外出
  74. CheckInDataView checkInDataView = new CheckInDataView();
  75. checkInDataView = await _qiYeWeChatApiService.GetCheckinDataAsync(qyWhchatIdList, 2,startDt, endDt);
  76. if (checkInDataView.errcode != 0)
  77. {
  78. _result.Msg = "【企业微信】【打卡】【获取时间段内所有日打卡记录】【Msg】" + checkInDataView.errmsg;
  79. return _result;
  80. }
  81. //筛选出工作日日报
  82. List<Root> workday_userRoots = checkInDayDataView.datas.Where(it => it.base_info.day_type == 0 && it.base_info.record_type == 1).ToList();
  83. //工作日日报
  84. workday_userRoots = workday_userRoots.OrderBy(it => it.base_info.date).ToList();
  85. //获取 请假类型 Sp_Detail.template_id
  86. string leave_template_id = "C4NzTJCh1onCUK915rRkvy7Fh5Vqz4YbiEV9jrBY1";
  87. List<VacationLeaveTypeView> vacationLeaveTypes = await GetVacationLeaveTypes(leave_template_id);
  88. if (vacationLeaveTypes.Count <= 0)
  89. {
  90. _result.Msg = "【企业微信】【审批】【获取审批类型】【Msg】" + startDt + " - " + endDt + "请假 类型数据 获取失败!";
  91. return _result;
  92. }
  93. try
  94. {
  95. foreach (var pm_wsInfo in pm_WageSheetDattaSources)
  96. {
  97. string itemName = userNames.Where(it => it.Id == pm_wsInfo.UserId).FirstOrDefault().CnName;
  98. //补贴 金额
  99. decimal meal_subsidy = 0.00M; // 午餐(午餐10元/天) 补贴 * 计算方式:单日上午请假时长(小时)大于或者等于三小时 没有餐补
  100. //事假 病假 总金额
  101. decimal personalLeaveTotal = 0.00M, // 事假 日薪 *计算方式:日平均工资 = 月工资/当月应出勤天数。
  102. sickLeaveTotal = 0.00M; // 病假 日薪 *计算方式:日平均工资 = 成都市最低工资标准的80%/当月应出勤天数。 短期病假=当月15天内
  103. //扣款金额
  104. decimal beLate_deduction = 0.00M, // 迟到 扣款金额 *计算方式:
  105. // 一个自然月内,不足 10 分钟的迟到/早退,不超过 2 次的部分,不做处罚;3 次及以上,按50元 / 次处罚;
  106. // 超过 10 分钟(含 10 分钟),不足 60 分钟的迟到/早退,按 50 元/次处罚;
  107. // 超过 60 分钟(含 60 分钟),不足 3 小时的迟到/早退,且无请假者,按旷工半日处理;超过3 小时的迟到 / 早退,且无请假者,按旷工一日处理。
  108. early_deduction = 0.00M, // 早退 扣款金额
  109. absenteeism_deduction = 0.00M, // 旷工 扣款金额 *计算方式:旷工扣发当日工资
  110. unprinted_deduction = 0.00M, // 未打卡 扣款金额 *计算方式:
  111. // 试用期员工每月有 2 次 补卡机会,超过 2 次不足 5 次的部分,按 10 元 / 次处罚,5 次及以上的漏卡,按 50 元 / 次处罚;
  112. // 正式员工每月 3 次以内的补卡,按 10 元 / 次处罚,3 次及以上的漏卡,按 50 元 / 次处罚。
  113. sickLeave_deduction = 0.00M, // 病假
  114. other_deduction = 0.00M; // 其他 扣款金额
  115. decimal meal_deduction = 0.00M; // 餐补 扣款金额
  116. decimal reissuecard_deduction = 0.00M; // 补卡 扣款金额
  117. #region 计算日工资 正常日薪 事假日薪 病假日薪
  118. //月 - 应发工资
  119. decimal amountPayable = pm_wsInfo.Basic + pm_wsInfo.Floats + pm_wsInfo.PostAllowance + pm_wsInfo.InformationSecurityFee + pm_wsInfo.OtherSubsidies;
  120. // 日薪 = *计算方式:日平均工资 = 月工资/当月应出勤天数。
  121. decimal dailyWage = amountPayable / work_days;
  122. // 病假日薪 *计算方式:日平均工资 = 成都市最低工资标准的80%/当月应出勤天数。 短期病假=当月15天内
  123. decimal sickLeave_dailywage = _chengDuMinimumWage / work_days;
  124. //病假 一天扣款
  125. sickLeave_deduction = dailyWage - sickLeave_dailywage;
  126. List<Ex_Items> ex_Items = new List<Ex_Items>();//假勤 And 打卡备注集合
  127. Ex_Items ex_Items_dk = new Ex_Items() { Type = "打卡" }; //打卡
  128. Ex_Items ex_Items_jq = new Ex_Items() { Type = "假勤" }; //假勤
  129. #endregion
  130. List<Root> userRoots = new List<Root>();
  131. if (itemName == "蔡雯")
  132. {
  133. userRoots = workday_userRoots.Where(it => it.base_info.name == "蔡蔡" || it.base_info.name == "蔡雯").ToList(); //工作日日报 1-固定上下班;
  134. }
  135. else
  136. {
  137. userRoots = workday_userRoots.Where(it => it.base_info.name == itemName).ToList(); //工作日日报 1-固定上下班;
  138. }
  139. //userRoots = userRoots.Distinct().ToList();
  140. userRoots = userRoots.OrderBy(it => it.base_info.date).ToList();
  141. int dk_work_days = userRoots.Count; //应出勤天数
  142. if (dk_work_days > work_days)
  143. {
  144. dk_work_days = work_days;
  145. }
  146. meal_subsidy = dk_work_days * 10; //应发放餐补
  147. if (!itemName.Equals("张海麟"))
  148. {
  149. if (userRoots.Count <= 0)
  150. {
  151. _result.Msg = "【企业微信】【打卡】【获取打卡数据】【Msg】" + startDt + " - " + endDt + "打卡日数据 获取失败!";
  152. continue;
  153. }
  154. string acctid = userRoots[0].base_info.acctid;
  155. List<Ex_Item> ex_reissuecard_Items = new List<Ex_Item>(); //打卡类型 数据
  156. List<Sp_items> acc_sp_items = new List<Sp_items>(); //审批数据
  157. int user_probationary_bk_num = 0;
  158. decimal user_probationary_bk_decimal = pm_wsInfo.Floats; //绩效工资为0 则为试用员工
  159. //处理外出打卡记录
  160. List<CheckInDataInfo> checkInData1 = new List<CheckInDataInfo>();
  161. checkInData1 = checkInDataView.checkindata;
  162. List<CheckInDataInfo> checkInDatas = new List<CheckInDataInfo>();
  163. checkInDatas = checkInData1.Where(it => it.userid == acctid).ToList();
  164. #region 迟到 早退 旷工
  165. int user_cd_zt_num = 0; //早退/迟到 次数 10分钟内 2次以内不记处罚 三次及以上50一次
  166. foreach (var root in userRoots)
  167. {
  168. List<Holiday_infos> holiday_Infos = root.holiday_infos; //当天假勤信息
  169. List<Exception_infos> exception_infos = root.exception_infos; //当天校准状态信息
  170. List<Sp_items> sp_Items = root.sp_items;//当天假勤统计信息
  171. if (sp_Items.Count > 0)
  172. {
  173. sp_Items = sp_Items.Where(it => it.count > 0).ToList();
  174. acc_sp_items.AddRange(sp_Items);
  175. }
  176. foreach (var exception_info in exception_infos)
  177. {
  178. decimal timelength = ConvertToDecimal((Convert.ToDecimal(exception_info.duration) / 3600.00M) * 60.00M); //时长 分钟
  179. if (timelength == 9) timelength = 7.50M;
  180. int exception = exception_info.exception; //异常类型
  181. decimal day_miner_unit = dailyWage / 15; //以0.5小时为单位
  182. //1:一个自然月内,不足 10 分钟的迟到/早退,不超过 2 次的部分,不做处罚;3 次及以上,按50 元 / 次处罚;
  183. //2:超过 10 分钟(含 10 分钟),不足 60 分钟的迟到 / 早退,按 50 元 / 次处罚;
  184. //3:超过 60 分钟(含 60 分钟),不足 3 小时的迟到 / 早退,且无请假者,按旷工半日处理;超过 3 小时的迟到 / 早退,且无请假者,按旷工一日处理。
  185. long date = root.base_info.date; //当日工作日期
  186. long earliest_time = root.summary_info.earliest_time; //最早打卡时间
  187. long lastest_time = root.summary_info.lastest_time; //最晚打卡时间
  188. long this_date = date + earliest_time;
  189. DateTime thisDt = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)).AddTicks(this_date * 10000000);
  190. string thisDtStr = thisDt.ToString("yyyy-MM-dd");
  191. Ex_Item beLate_belate_ex = new Ex_Item()
  192. {
  193. SubTypeId = 4,
  194. SubType = "旷工",
  195. Duration = timelength,
  196. StartTimeDt = Convert.ToDateTime(root.base_info.dateDt.ToString("yyyy-MM-dd HH:mm:ss")),
  197. Unit = "分钟",
  198. };
  199. decimal day_deduction = 0.00M;
  200. //1 - 迟到;2 - 早退;3 - 缺卡;4 - 旷工;5 - 地点异常;6 - 设备异常
  201. if (exception == 1) //迟到
  202. {
  203. if (timelength < 10)
  204. {
  205. user_cd_zt_num++;
  206. beLate_belate_ex.SubTypeId = 1;
  207. beLate_belate_ex.SubType = "迟到";
  208. string thisStartDt = (TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)).AddTicks((date + earliest_time) * 10000000))
  209. .ToString("yyyy-MM-dd HH:mm:ss");
  210. beLate_belate_ex.StartTimeDt = Convert.ToDateTime(thisStartDt);
  211. if (user_cd_zt_num >= 3)
  212. {
  213. day_deduction = 50.00M;
  214. }
  215. else
  216. {
  217. day_deduction = 0.00M;
  218. }
  219. beLate_deduction += day_deduction; //迟到扣款 总额
  220. }
  221. else if (timelength >= 10 && timelength <= 60)
  222. {
  223. string thisStartDt = (TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1))
  224. .AddTicks((date + earliest_time) * 10000000))
  225. .ToString("yyyy-MM-dd HH:mm:ss");
  226. beLate_belate_ex.StartTimeDt = Convert.ToDateTime(thisStartDt);
  227. day_deduction = 50.00M;
  228. beLate_deduction += day_deduction; //迟到扣款 总额
  229. beLate_belate_ex.SubTypeId = 1;
  230. beLate_belate_ex.SubType = "迟到";
  231. }
  232. else if (timelength > 60 && timelength <= 180)
  233. {
  234. day_deduction = ConvertToDecimal(day_miner_unit * 6); //3小时
  235. meal_deduction += 10.00M; //餐补扣款
  236. absenteeism_deduction += day_deduction; //矿工半日
  237. }
  238. else
  239. {
  240. day_deduction = ConvertToDecimal(dailyWage);
  241. absenteeism_deduction += day_deduction; //矿工一日
  242. meal_deduction += 10.00M;
  243. }
  244. beLate_belate_ex.Deduction = day_deduction;
  245. ex_reissuecard_Items.Add(beLate_belate_ex);
  246. }
  247. else if (exception == 2) //早退
  248. {
  249. if (timelength < 10)
  250. {
  251. user_cd_zt_num++;
  252. beLate_belate_ex.SubTypeId = 2;
  253. beLate_belate_ex.SubType = "早退";
  254. string thisEndDt = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1))
  255. .AddTicks((date + lastest_time) * 10000000)
  256. .ToString("yyyy-MM-dd HH:mm:ss");
  257. beLate_belate_ex.StartTimeDt = Convert.ToDateTime(thisEndDt);
  258. if (user_cd_zt_num >= 3)
  259. {
  260. day_deduction = 50.00M;
  261. }
  262. else
  263. {
  264. day_deduction = 0.00M;
  265. }
  266. early_deduction += day_deduction; //早退扣款 总计
  267. }
  268. else if (timelength >= 10 && timelength <= 60)
  269. {
  270. day_deduction = 50.00M;
  271. early_deduction += day_deduction; //早退扣款 总计
  272. beLate_belate_ex.SubTypeId = 2;
  273. beLate_belate_ex.SubType = "早退";
  274. string thisEndDt = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1))
  275. .AddTicks((date + lastest_time) * 10000000)
  276. .ToString("yyyy-MM-dd HH:mm:ss");
  277. beLate_belate_ex.StartTimeDt = Convert.ToDateTime(thisEndDt);
  278. }
  279. else if (timelength > 60 && timelength <= 180)
  280. {
  281. day_deduction = ConvertToDecimal(day_miner_unit * 6); //3小时
  282. meal_deduction += 10.00M;
  283. absenteeism_deduction += day_deduction; //矿工半日
  284. }
  285. else
  286. {
  287. day_deduction = ConvertToDecimal(dailyWage);
  288. meal_deduction += 10.00M;
  289. absenteeism_deduction += day_deduction; //矿工一日
  290. }
  291. beLate_belate_ex.Deduction = day_deduction;
  292. ex_reissuecard_Items.Add(beLate_belate_ex);
  293. }
  294. else if (exception == 3) //缺卡
  295. {
  296. if (root.exception_infos.Count == 2)
  297. {
  298. day_deduction = dailyWage;
  299. meal_deduction += 10.00M;
  300. absenteeism_deduction += day_deduction;
  301. beLate_belate_ex.Reason = "上午-下午 缺卡/未打卡为旷工 一天";
  302. beLate_belate_ex.Deduction = day_deduction;
  303. ex_reissuecard_Items.Add(beLate_belate_ex);
  304. }
  305. else if (root.exception_infos.Count == 1)
  306. {
  307. if (earliest_time == lastest_time)
  308. {
  309. DateTime thisDt1 = Convert.ToDateTime(thisDtStr + " 12:00");
  310. if (thisDt <= thisDt1) //旷工 下午
  311. {
  312. day_deduction = ConvertToDecimal(day_miner_unit * 9); //4.5小时
  313. meal_deduction += 10.00M;
  314. beLate_belate_ex.Duration = 270;
  315. absenteeism_deduction += day_deduction; //矿工半日
  316. beLate_belate_ex.Reason = thisDtStr + " 下午(18:00)缺卡/未打卡视为下午旷工(4.5小时)";
  317. beLate_belate_ex.Deduction = day_deduction;
  318. ex_reissuecard_Items.Add(beLate_belate_ex);
  319. }
  320. else if (thisDt >= thisDt1) //旷工 上午
  321. {
  322. day_deduction = ConvertToDecimal(day_miner_unit * 6); //3小时
  323. meal_deduction += 10.00M;
  324. absenteeism_deduction += day_deduction; //矿工半日
  325. beLate_belate_ex.Duration = 180;
  326. beLate_belate_ex.Reason = thisDtStr + " 上午(09:00)缺卡/未打卡视为上午旷工(3小时)";
  327. beLate_belate_ex.Deduction = day_deduction;
  328. ex_reissuecard_Items.Add(beLate_belate_ex);
  329. }
  330. else //矿工一日
  331. {
  332. day_deduction = ConvertToDecimal(dailyWage);
  333. meal_deduction += 10.00M;
  334. absenteeism_deduction += day_deduction;
  335. beLate_belate_ex.Reason = thisDtStr + " 上午(09:00)-下午(18:00) 缺卡/未打视为旷工一天(7.5小时)";
  336. beLate_belate_ex.Deduction = day_deduction;
  337. ex_reissuecard_Items.Add(beLate_belate_ex);
  338. }
  339. }
  340. }
  341. }
  342. else if (exception == 4) //旷工
  343. {
  344. if (timelength > 60 && timelength <= 180)
  345. {
  346. day_deduction = ConvertToDecimal(day_miner_unit * 6); //3小时
  347. beLate_belate_ex.Reason = thisDtStr + " 缺卡/未打视为旷工上午(3小时)";
  348. meal_deduction += 10.00M;
  349. absenteeism_deduction += day_deduction; //矿工半日
  350. }
  351. else
  352. {
  353. day_deduction = ConvertToDecimal(dailyWage);
  354. beLate_belate_ex.Reason = thisDtStr + " 上午(09:00)-下午(18:00) 缺卡/未打视为旷工一天(7.5小时)";
  355. meal_deduction += 10.00M;
  356. absenteeism_deduction += day_deduction; //矿工一日
  357. }
  358. beLate_belate_ex.Deduction = day_deduction;
  359. ex_reissuecard_Items.Add(beLate_belate_ex);
  360. }
  361. }
  362. }
  363. //外出打卡 计算旷工迟到
  364. foreach (var checkInData in checkInDatas)
  365. {
  366. //当前时间是上午还是下午
  367. int timeLong = 0;
  368. string thisTime = string.Format(@"12:00:00");
  369. string wcdkTime = checkInData.checkin_time_dt.ToString("HH:mm:ss");
  370. DateTime wcdkDt = Convert.ToDateTime(wcdkTime);
  371. if (Convert.ToDateTime(thisTime) > wcdkDt) //上午
  372. {
  373. DateTime amDt = Convert.ToDateTime("09:00:00");
  374. if (wcdkDt <= amDt)
  375. {
  376. continue;
  377. }
  378. }
  379. else
  380. {
  381. DateTime pmDt = Convert.ToDateTime("18:00:00");
  382. if (wcdkDt >= pmDt)
  383. {
  384. continue;
  385. }
  386. }
  387. }
  388. #endregion
  389. #region 假勤/补卡次数 审批
  390. int leaveNum = 0; //请假次数
  391. int reissuecardNum = 0; //补卡次数\
  392. //类型:1 - 请假;2 - 补卡;3 - 出差;4 - 外出;100 - 外勤
  393. leaveNum = acc_sp_items.Where(it => it.type == 1).ToList().Count();
  394. reissuecardNum = acc_sp_items.Where(it => it.type == 2).ToList().Count();
  395. //请假审批
  396. if (leaveNum > 0)
  397. {
  398. List<Sp_Detail> sp_leave_details = new List<Sp_Detail>();
  399. sp_leave_details = await _qiYeWeChatApiService.GetApprovalDetailsAsync(startDt, endDt, acctid, 2, 1); //时间段内所有 已同意的 请假 审批数据
  400. if (sp_leave_details.Count <= 0)
  401. {
  402. _result.Msg += startDt + " - " + endDt + " " + itemName + " 请假 审批数据获取未获取到!\r\n";
  403. //continue;
  404. }
  405. List<Ex_Item> ex_ItemInfos = new List<Ex_Item>();
  406. List<LeaveDetails> leaveDetails = new List<LeaveDetails>();
  407. foreach (Sp_Detail sp_item in sp_leave_details)
  408. {
  409. Apply_data? apply_data = sp_item.apply_data;
  410. if (apply_data != null)
  411. {
  412. List<ContentsItem> contents = apply_data.contents;
  413. ContentsItem content_Vacation = contents.Where(it => it.control == "Vacation").FirstOrDefault(); //请假类型
  414. ContentsItem content_Textarea = contents.Where(it => it.control == "Textarea").FirstOrDefault(); //多行文本
  415. if (content_Vacation != null)
  416. {
  417. Vacation vacation = content_Vacation.value.vacation;
  418. Attendance attendance = vacation.attendance; //假勤组件
  419. Selector selector = vacation.selector; //请假类型
  420. List<OptionsItem> optionsItems = selector.options; //key 请假类型 id
  421. List<TitleItem> value = optionsItems[0].value; // value 文本描述值
  422. int leaveType = int.Parse(optionsItems[0].key); //key 请假子类型 id
  423. Date_range date_Range = attendance.date_range;
  424. //筛选 不在工作日内的假勤申请
  425. if (startDt >= date_Range.new_begin_dt || Convert.ToDateTime( date_Range.new_end_dt.ToString("yyyy-MM-dd")) > endDt)
  426. {
  427. continue;
  428. }
  429. string leave_starttime = date_Range.new_begin_dt.ToString("HH:mm");
  430. string leave_endtime = date_Range.new_end_dt.ToString("HH:mm");
  431. string typeName = string.Empty;
  432. string unit = string.Empty;
  433. int leaveTypeId = leaveType;
  434. var leaveTypeData = vacationLeaveTypes.Where(it => it.id == leaveTypeId).FirstOrDefault();
  435. if (leaveTypeData != null) { typeName = leaveTypeData.name; }
  436. string startTime = string.Empty;
  437. string endTime = string.Empty;
  438. string startTime1 = string.Empty;
  439. string endTime1 = string.Empty;
  440. //计算请假类型扣款金额
  441. decimal new_duration = 0.00M;
  442. if (date_Range.type == "halfday")
  443. {
  444. new_duration = Convert.ToDecimal(date_Range.new_duration) / 86400.00M;
  445. unit = "天";
  446. startTime = date_Range.new_begin_dt.ToString("yyyy-MM-dd") + " 09:00";
  447. endTime = date_Range.new_begin_dt.ToString("yyyy-MM-dd") + " 18:00";
  448. startTime1 = "09:00:00";
  449. endTime1 = "18:00:00";
  450. }
  451. else if (date_Range.type == "hour")
  452. {
  453. new_duration = Convert.ToDecimal(date_Range.new_duration) / 3600.00M;
  454. unit = "小时";
  455. startTime = date_Range.new_begin_dt.ToString("yyyy-MM-dd HH:mm:ss");
  456. endTime = date_Range.new_end_dt.ToString("yyyy-MM-dd HH:mm:ss");
  457. startTime1 = date_Range.new_begin_dt.ToString("HH:mm:ss");
  458. endTime1 = date_Range.new_end_dt.ToString("HH:mm:ss");
  459. }
  460. LeaveDetails leaveDetails1 = new LeaveDetails()
  461. {
  462. TypeId = leaveType,
  463. TypeName = typeName,
  464. StartDt = Convert.ToDateTime(date_Range.new_begin_dt.ToString("yyyy-MM-dd") + " " + startTime1),
  465. EndDt = Convert.ToDateTime(date_Range.new_end_dt.ToString("yyyy-MM-dd") + " " + endTime1),
  466. DtType = date_Range.type,
  467. Unit = unit,
  468. New_Duration = new_duration,
  469. ApplyDt = Convert.ToDateTime(sp_item.apply_time_dt.ToString("yyyy-MM-dd HH:mm:ss"))
  470. };
  471. leaveDetails.Add(leaveDetails1);
  472. }
  473. }
  474. }
  475. if (leaveDetails.Count > 0)
  476. {
  477. foreach (LeaveDetails leave_item in leaveDetails)
  478. {
  479. decimal leave_meals = 0.00M;
  480. decimal thisTypeDeduction = 0.00M;//当前类型扣款
  481. int leaveType = leave_item.TypeId;
  482. decimal new_duration = leave_item.New_Duration;
  483. //计算餐补 假勤类型扣款
  484. CalculateTypeFee(leaveDetails,leaveType, leave_item.DtType, leave_item.StartDt, leave_item.EndDt, amountPayable, work_days,
  485. new_duration,out leave_meals, out thisTypeDeduction);
  486. #region 累计类型扣款
  487. //1年假;2事假;3病假;4调休假;5婚假;6产假;7陪产假;8其他;9丧假
  488. if (leaveType == 2) //事假
  489. {
  490. personalLeaveTotal += thisTypeDeduction;
  491. }
  492. else if (leaveType == 3) //病假
  493. {
  494. sickLeaveTotal = thisTypeDeduction;
  495. }
  496. #endregion
  497. meal_deduction += leave_meals;
  498. Ex_Item ex_Item = new Ex_Item()
  499. {
  500. SubTypeId = leaveType,
  501. SubType = leave_item.TypeName,
  502. StartTimeDt = leave_item.StartDt,
  503. EndTimeDt = leave_item.EndDt,
  504. Duration = new_duration,
  505. Unit = leave_item.Unit,
  506. Deduction = thisTypeDeduction,
  507. //Reason = apply_data.reason,
  508. Apply_time_dt = leave_item.ApplyDt,
  509. //Approval_name = sp_item.approval_name,
  510. };
  511. ex_ItemInfos.Add(ex_Item);
  512. }
  513. }
  514. if (ex_ItemInfos.Count > 0)
  515. {
  516. ex_Items_jq.Ex_ItemInfo = ex_ItemInfos.OrderBy(it => it.StartTimeDt).ThenBy(it => it.Apply_time_dt).ToList();
  517. ex_Items.Add(ex_Items_jq);
  518. }
  519. }
  520. //打卡补卡
  521. //补卡:员工发现自己漏打卡时,需及时提起补卡申请,并说明情况。
  522. //试用期员工每月有 2 次补卡机会,超过 2 次不足 5 次的部分,按 10 元/次处罚,5 次及以上的漏卡,按 50 元/次处罚;
  523. //正式员工每月 3 次以内的补卡,按 10 元/次处罚,3 次及以上的漏卡,按 50 元/次处罚。
  524. if (reissuecardNum > 0)
  525. {
  526. List<Sp_Detail> sp_buka_details = new List<Sp_Detail>();
  527. sp_buka_details = await _qiYeWeChatApiService.GetApprovalDetailsAsync(startDt, endDt, acctid, 2, 2); //时间段内所有 已同意的 请假 审批数据
  528. int bukaNum = 1;
  529. foreach (var item in sp_buka_details)
  530. {
  531. Apply_data? apply_data = item.apply_data;
  532. if (apply_data != null)
  533. {
  534. List<ContentsItem> contents = apply_data.contents;
  535. ContentsItem content_Vacation = contents.Where(it => it.control == "PunchCorrection").FirstOrDefault(); //请假类型
  536. ContentsItem content_Textarea = contents.Where(it => it.control == "Textarea").FirstOrDefault(); //多行文本
  537. if (content_Vacation != null)
  538. {
  539. var punch_correction = content_Vacation.value.punch_correction;
  540. DateTime bukaDt = punch_correction.time_dt;
  541. DateTime bukaDtJudge = Convert.ToDateTime(bukaDt.ToString("yyyy-MM-dd"));
  542. //筛选 不在工作日内的假勤申请
  543. if (startDt >= bukaDtJudge || bukaDtJudge > endDt)
  544. {
  545. continue;
  546. }
  547. decimal bukaPrice = 0.00M;
  548. if (user_probationary_bk_decimal == 0) //计算试用员工补卡次数
  549. {
  550. if (bukaNum <= 2) bukaPrice = 0.00M;
  551. else if (bukaNum <= 4 && bukaNum > 2) bukaPrice = 10.00M;
  552. else bukaPrice = 50.00M;
  553. }
  554. else //计算正式员工补卡次数
  555. {
  556. if (bukaNum <= 2) bukaPrice = 10.00M;
  557. else bukaPrice = 50.00M;
  558. }
  559. var app_data = item.apply_data;
  560. var punch_correction1 = app_data.contents[0].value.punch_correction; //未打卡时间
  561. var punch_correction2 = app_data.contents[1].value;
  562. Ex_Item ex_reissueCard = new Ex_Item()
  563. {
  564. SubTypeId = 7,
  565. SubType = "打卡补卡",
  566. StartTimeDt = Convert.ToDateTime(punch_correction1.time_dt.ToString("yyyy-MM-dd HH:mm:ss")), //未打卡时间
  567. Deduction = bukaPrice,
  568. Reason = punch_correction2.text,
  569. Unit = string.Empty
  570. };
  571. unprinted_deduction += bukaPrice;
  572. ex_reissuecard_Items.Add(ex_reissueCard);
  573. bukaNum++;
  574. }
  575. }
  576. }
  577. }
  578. if (ex_reissuecard_Items.Count > 0)
  579. {
  580. ex_Items_dk.Ex_ItemInfo = ex_reissuecard_Items;
  581. //ex_Items_dk.Ex_ItemInfo = ex_reissuecard_Items.OrderBy(it => it.SubTypeId).ThenBy(it => it.StartTimeDt).ToList();
  582. ex_Items.Add(ex_Items_dk);
  583. }
  584. #endregion
  585. }
  586. else
  587. {
  588. meal_subsidy = work_days * 10.00M;
  589. }
  590. #region 应发合计 实发合计 扣款合计(假勤扣款,其他扣款,社保扣款,公积金代扣,个税扣款)
  591. decimal mealTotal = meal_subsidy - meal_deduction; //餐补
  592. decimal salaryTotal = 0.00M;
  593. if (dk_work_days >= work_days)
  594. {
  595. dk_work_days = work_days;
  596. salaryTotal = amountPayable + mealTotal; //应发合计
  597. }
  598. else
  599. {
  600. if (itemName.Equals("张海麟"))
  601. {
  602. salaryTotal = amountPayable + mealTotal; //应发合计
  603. }
  604. else
  605. {
  606. salaryTotal = (dk_work_days * dailyWage) + mealTotal; //应发合计
  607. }
  608. }
  609. //扣款合计 不含个税
  610. decimal eductionTotal = sickLeaveTotal + personalLeaveTotal + beLate_deduction + early_deduction + absenteeism_deduction + unprinted_deduction + other_deduction +
  611. pm_wsInfo.WithholdingInsurance + pm_wsInfo.ReservedFunds + pm_wsInfo.OtherDeductions;
  612. decimal actualReleaseTotal = salaryTotal - eductionTotal; //实发合计 * 不含个税
  613. #endregion
  614. #region 处理当月工资数据
  615. pm_wsInfo.YearMonth = thisYearMonth;
  616. pm_wsInfo.StartDate = startDt.ToString("yyyy-MM-dd");
  617. pm_wsInfo.EndDate = endDt.ToString("yyyy-MM-dd");
  618. pm_wsInfo.WorkDays = work_days; //当月应出勤天数
  619. pm_wsInfo.RegularDays = dk_work_days; //当月正常出勤天数
  620. pm_wsInfo.SickLeave = sickLeaveTotal; //病假
  621. pm_wsInfo.SomethingFalse = personalLeaveTotal; //事假
  622. pm_wsInfo.LateTo = beLate_deduction; //迟到
  623. pm_wsInfo.LeaveEarly = early_deduction; //早退
  624. pm_wsInfo.Absenteeism = absenteeism_deduction; //旷工
  625. pm_wsInfo.NotPunch = unprinted_deduction; //未打卡
  626. pm_wsInfo.OtherDeductions = other_deduction; //其他
  627. pm_wsInfo.Ex_ItemsRemark = JsonConvert.SerializeObject(ex_Items); //
  628. pm_wsInfo.Mealsupplement = mealTotal; //餐补
  629. pm_wsInfo.Should = salaryTotal; //应发合计
  630. pm_wsInfo.TotalDeductions = eductionTotal; //扣款合计
  631. pm_wsInfo.TotalRealHair = actualReleaseTotal - pm_wsInfo.WithholdingTax; //实发合计
  632. pm_wsInfo.AfterTax = actualReleaseTotal - pm_wsInfo.WithholdingTax; //税后工资
  633. pm_wsInfo.LastUpdateUserId = userId;
  634. pm_wsInfo.LastUpdateDt = DateTime.Now;
  635. pm_wsInfo.CreateUserId = userId;
  636. pm_wsInfo.CreateTime = DateTime.Now;
  637. pm_wsInfo.DeleteUserId = null;
  638. pm_wsInfo.DeleteTime = null;
  639. #endregion
  640. }
  641. }
  642. catch (Exception ex)
  643. {
  644. _result.Msg = ex.Message;
  645. return _result;
  646. }
  647. _result.Code = 0;
  648. _result.Data = pm_WageSheetDattaSources;
  649. return _result;
  650. }
  651. /// <summary>
  652. /// decimal 保留两位小数 不四舍五入
  653. /// </summary>
  654. /// <param name="number"></param>
  655. /// <returns></returns>
  656. public static decimal ConvertToDecimal(decimal myDecimal)
  657. {
  658. var subDecimal = Math.Floor(myDecimal * 100) / 100;//保留两位小数,直接截取
  659. return subDecimal;
  660. }
  661. /// <summary>
  662. /// 获取请假类型
  663. /// </summary>
  664. /// <param name="template_id"></param>
  665. /// <returns></returns>
  666. public static async Task<List<VacationLeaveTypeView>> GetVacationLeaveTypes(string template_id)
  667. {
  668. List<VacationLeaveTypeView> vacationLeaveTypes = new List<VacationLeaveTypeView>();
  669. TemplateDetailView templateDetailView = new TemplateDetailView();
  670. templateDetailView = await _qiYeWeChatApiService.GetTemplateDetailAsync(template_id);
  671. if (templateDetailView.errcode != 0)
  672. {
  673. Serilog.Log.Error("【企业微信】【审批】【获取假勤类型的审批】【Msg】"+ templateDetailView.errmsg);
  674. return vacationLeaveTypes;
  675. }
  676. List<VacationItemInfo> VacationItemInfos = templateDetailView.vacation_list.item;
  677. foreach (var item in VacationItemInfos)
  678. {
  679. ValueItem valueInfo = item.name.Where(it => it.lang == "zh_CN").FirstOrDefault();
  680. if (valueInfo != null)
  681. {
  682. vacationLeaveTypes.Add(
  683. new VacationLeaveTypeView()
  684. {
  685. id = item.id,
  686. name = valueInfo.text
  687. });
  688. }
  689. }
  690. return vacationLeaveTypes;
  691. }
  692. /// <summary>
  693. /// 计算类型费用
  694. /// </summary>
  695. /// <param name="leaveType">
  696. /// 1年假;2事假;3病假;4调休假;5婚假;6产假;7陪产假;8其他;9丧假
  697. /// </param>
  698. /// <param name="date_Range_type">
  699. /// halfday 全天
  700. /// hour 小时
  701. /// </param>
  702. /// <param name="startTime"></param>
  703. /// <param name="endTime"></param>
  704. /// <param name="duration"></param>
  705. /// <param name="mealDeduction"></param>
  706. /// <param name="typeDeduction"></param>
  707. public static void CalculateTypeFee(List<LeaveDetails> leaveDetails,int leaveType, string date_Range_type, DateTime startTime, DateTime endTime,
  708. decimal amountPayable,int work_days, decimal duration, out decimal mealDeduction, out decimal typeDeduction)
  709. {
  710. typeDeduction = 0;
  711. mealDeduction = 0;
  712. string am_starttime = "08:59";
  713. string am_endtime = "13:01";
  714. //string startTime = startTime1.ToString("HH:mm:ss");
  715. //string endTime = endTime1.ToString("HH:mm:ss");
  716. decimal personalkLeave_dailywage_day = amountPayable / work_days; //日薪 = 事假日薪 *计算方式:日平均工资 = 当月应发工资 /当月应出勤天数。
  717. //半小时单位
  718. decimal halfHour = 7.50M / 0.50M;
  719. switch (leaveType)
  720. {
  721. case 1: //年假
  722. CalculateTypeFeeSub(leaveDetails, date_Range_type, startTime, endTime, duration, out mealDeduction);
  723. break;
  724. case 2: //2事假
  725. // 事假日薪 *计算方式:日平均工资 = 当月应发工资 /当月应出勤天数。
  726. decimal personalkLeave_dailywage_halfhour = personalkLeave_dailywage_day / halfHour; //事假单位 0.5小时
  727. if (date_Range_type == "halfday")
  728. {
  729. mealDeduction = 10; //餐补扣款
  730. typeDeduction = ConvertToDecimal(personalkLeave_dailywage_day);
  731. }
  732. else if (date_Range_type == "hour")
  733. {
  734. decimal leave_halfHour = Convert.ToDecimal(duration) / Convert.ToDecimal(0.5);
  735. typeDeduction = ConvertToDecimal( personalkLeave_dailywage_halfhour * leave_halfHour);
  736. //duration = 11M;
  737. if (duration >= 3 && duration < 7.5M) //单天请假三小时
  738. {
  739. mealDeduction = 10; //餐补扣款
  740. }
  741. else if (duration >= 7.5M) //多天计算
  742. {
  743. decimal leave_halfHour1 = Convert.ToDecimal(duration) / Convert.ToDecimal(0.5);
  744. decimal leaveDays = duration / 7.5M;
  745. if (leaveDays % 1 == 0)
  746. {
  747. typeDeduction = ConvertToDecimal(personalkLeave_dailywage_day * leaveDays);
  748. mealDeduction = 10 * leaveDays; //餐补扣款
  749. }
  750. else
  751. {
  752. typeDeduction = personalkLeave_dailywage_day * Convert.ToInt32(leaveDays);
  753. decimal sy_shijiaunit = leave_halfHour1 - Convert.ToDecimal (15.00M * Convert.ToInt32(leaveDays));
  754. if (sy_shijiaunit > 0)
  755. {
  756. typeDeduction += ConvertToDecimal(personalkLeave_dailywage_halfhour * sy_shijiaunit);
  757. }
  758. mealDeduction = 10 * Convert.ToInt32(leaveDays);
  759. //得到最后一天的请假时间 是否有餐补
  760. int lastHours = (Convert.ToDateTime(endTime) - Convert.ToDateTime("09:00")).Hours;
  761. if (lastHours >= 3)
  762. {
  763. mealDeduction += 10; //餐补扣款
  764. }
  765. }
  766. }
  767. }
  768. break;
  769. case 3: //3病假
  770. // 病假日薪 *计算方式:日平均工资 = 成都市最低工资标准的80% /当月应出勤天数。 短期病假=当月15天内
  771. decimal chengDuMinimumWage_halrHour = _chengDuMinimumWage / work_days / halfHour;
  772. decimal sickLeave_dailywage_halfhour_deduction = personalkLeave_dailywage_day - chengDuMinimumWage_halrHour; //病假单位 0.5小时 扣款金额
  773. if (date_Range_type == "halfday")
  774. {
  775. mealDeduction = 10; //餐补扣款
  776. typeDeduction = ConvertToDecimal( sickLeave_dailywage_halfhour_deduction * halfHour);
  777. }
  778. else if (date_Range_type == "hour")
  779. {
  780. decimal sickLeave_halfHour = duration / 0.5M;
  781. typeDeduction = ConvertToDecimal(personalkLeave_dailywage_day); ;
  782. if (duration >= 3 && duration < 7.5M) //单天请假三小时 && 请假时间在上午 则没有餐补
  783. {
  784. mealDeduction = 10; //餐补扣款
  785. }
  786. else if (duration >= 7.5M) //多天计算
  787. {
  788. decimal sickLeave_halfHour1 = duration / 0.5M;
  789. decimal leaveDays = Convert.ToDecimal(duration / 7.5M);
  790. typeDeduction = ConvertToDecimal(sickLeave_dailywage_halfhour_deduction * sickLeave_halfHour1);
  791. if (leaveDays % 1 == 0)
  792. {
  793. mealDeduction = 10 * leaveDays; //餐补扣款
  794. }
  795. else
  796. {
  797. mealDeduction = 10 * Convert.ToInt32(leaveDays);
  798. typeDeduction = ConvertToDecimal(sickLeave_dailywage_halfhour_deduction * Convert.ToInt32(leaveDays));
  799. decimal sy_bingjiaunit = sickLeave_halfHour1 - Convert.ToDecimal(15.00M * Convert.ToInt32(leaveDays));
  800. if (sy_bingjiaunit > 0)
  801. {
  802. typeDeduction += ConvertToDecimal(sickLeave_dailywage_halfhour_deduction * sy_bingjiaunit);
  803. }
  804. //得到最后一天的请假时间 是否有餐补
  805. int lastHours = (Convert.ToDateTime(endTime) - Convert.ToDateTime("09:00")).Hours;
  806. if (lastHours >= 3)
  807. {
  808. mealDeduction += 10; //餐补扣款
  809. }
  810. }
  811. }
  812. }
  813. break;
  814. case 4: //4调休假
  815. CalculateTypeFeeSub(leaveDetails,date_Range_type, startTime, endTime, duration, out mealDeduction);
  816. break;
  817. case 5: //5婚假
  818. CalculateTypeFeeSub(leaveDetails,date_Range_type, startTime, endTime, duration, out mealDeduction);
  819. break;
  820. case 6: //6产假
  821. CalculateTypeFeeSub(leaveDetails,date_Range_type, startTime, endTime, duration, out mealDeduction);
  822. break;
  823. case 7: //7陪产假
  824. CalculateTypeFeeSub(leaveDetails,date_Range_type, startTime, endTime, duration, out mealDeduction);
  825. break;
  826. case 8: //8其他
  827. CalculateTypeFeeSub(leaveDetails,date_Range_type, startTime, endTime, duration, out mealDeduction);
  828. break;
  829. case 9: //9丧假
  830. CalculateTypeFeeSub(leaveDetails,date_Range_type, startTime, endTime, duration, out mealDeduction);
  831. break;
  832. }
  833. }
  834. /// <summary>
  835. /// 计算类型费用
  836. /// </summary>
  837. /// <param name="date_Range_type">
  838. /// halfday 全天
  839. /// hour 小时
  840. /// </param>
  841. /// <param name="startTime"></param>
  842. /// <param name="endTime"></param>
  843. /// <param name="duration"></param>
  844. /// <param name="mealDeduction"></param>
  845. public static void CalculateTypeFeeSub(List<LeaveDetails> leaveDetails,string date_Range_type, DateTime startTime1, DateTime endTime1,
  846. decimal duration, out decimal mealDeduction)
  847. {
  848. mealDeduction = 0;
  849. string am_starttime = "09:00";
  850. string am_endtime = "11:59";
  851. string startTime = startTime1.ToString("HH:mm:ss");
  852. string endTime = endTime1.ToString("HH:mm:ss");
  853. if (date_Range_type == "halfday")
  854. {
  855. mealDeduction = 10; //餐补扣款
  856. }
  857. else if (date_Range_type == "hour")
  858. {
  859. List<LeaveDetails> leaveDetails1 = new List<LeaveDetails>();
  860. leaveDetails1 = leaveDetails.Where(it => it.StartDt.ToString("yyyy-MM-dd").Equals(startTime1.ToString("yyyy-MM-dd")))
  861. .OrderBy(it => it.StartDt).ToList();
  862. if (leaveDetails1.Count > 1)
  863. {
  864. decimal timelenTatoal = leaveDetails1.Sum(it => it.New_Duration);
  865. if (timelenTatoal >= 3.00M)
  866. {
  867. if (leaveDetails1[0].StartDt == startTime1)
  868. {
  869. mealDeduction = 10; //餐补扣款
  870. }
  871. }
  872. }
  873. else
  874. {
  875. if (duration >= 3 && duration < 7) //单天请假三小时 && 请假时间在上午 则没有餐补
  876. {
  877. mealDeduction = 10; //餐补扣款
  878. }
  879. else if (duration >= 7 && duration <= 7.50M)
  880. {
  881. mealDeduction = 10; //餐补扣款
  882. }
  883. else if (duration >= 7.50M) //多天计算
  884. {
  885. decimal leaveDays = Convert.ToDecimal(duration / 7.50M);
  886. if (leaveDays % 1 == 0)
  887. {
  888. mealDeduction = 10 * leaveDays; //餐补扣款
  889. }
  890. else
  891. {
  892. mealDeduction = 10 * Convert.ToInt32(leaveDays);
  893. //得到最后一天的请假时间 是否有餐补
  894. int lastHours = (Convert.ToDateTime(endTime) - Convert.ToDateTime("09:00")).Hours;
  895. if (lastHours >= 3)
  896. {
  897. mealDeduction += 10; //餐补扣款
  898. ////处理结束时间
  899. //if (endTime.CompareTo(am_starttime) > 0 && endTime.CompareTo(am_endtime) < 0)
  900. //{
  901. // mealDeduction += 10; //餐补扣款
  902. //}
  903. }
  904. }
  905. }
  906. }
  907. }
  908. }
  909. /// <summary>
  910. /// 获取打卡补卡类型
  911. /// </summary>
  912. /// <param name="template_id"></param>
  913. /// <returns></returns>
  914. public static async Task<List<VacationLeaveTypeView>> GetVacationReissueCardTypes(string template_id)
  915. {
  916. List<VacationLeaveTypeView> vacationLeaveTypes = new List<VacationLeaveTypeView>();
  917. TemplateDetailView templateDetailView = new TemplateDetailView();
  918. templateDetailView = await _qiYeWeChatApiService.GetTemplateDetailAsync(template_id);
  919. if (templateDetailView.errcode != 0)
  920. {
  921. return vacationLeaveTypes;
  922. }
  923. List<VacationItemInfo> VacationItemInfos = templateDetailView.vacation_list.item;
  924. foreach (var item in VacationItemInfos)
  925. {
  926. ValueItem valueInfo = item.name.Where(it => it.lang == "zh_CN").FirstOrDefault();
  927. if (valueInfo != null)
  928. {
  929. vacationLeaveTypes.Add(
  930. new VacationLeaveTypeView()
  931. {
  932. id = item.id,
  933. name = valueInfo.text
  934. });
  935. }
  936. }
  937. return vacationLeaveTypes;
  938. }
  939. /// <summary>
  940. /// 打卡数据
  941. /// 假勤数据 统计
  942. /// </summary>
  943. /// <param name="datas">数据源</param>
  944. /// <param name="type">
  945. /// 1-请假;2-补卡;3-出差;4-外出;100-外勤;
  946. /// </param>
  947. /// <param name="subTypeName">
  948. /// 年假 事假 病假 调休假 婚嫁 产假 陪产假 丧假 补卡次数 出差 外出数 外勤 其他
  949. /// </param>
  950. /// <returns></returns>
  951. private static int Fallibilitydispose(List<Sp_Item> datas, int type, string? subTypeName)
  952. {
  953. int num = 0;
  954. Sp_Item _Info = datas.Where(it => it.type == type && it.name == subTypeName).FirstOrDefault();
  955. if (_Info != null) { num = _Info.count; }
  956. return num;
  957. }
  958. /// <summary>
  959. /// 打卡数据
  960. /// 异常数据 统计
  961. /// </summary>
  962. /// <returns></returns>
  963. private static int ExceptionStatistics(List<Exception_Info> datas, int type)
  964. {
  965. int num = 0;
  966. Exception_Info _Info = datas.Where(it => it.exception == type).FirstOrDefault();
  967. if (_Info != null) { num = _Info.count; }
  968. return num;
  969. }
  970. /// <summary>
  971. /// 获取时间段内除周末 节假日外的 工作日
  972. /// </summary>
  973. /// <param name="startDt"></param>
  974. /// <param name="endDt"></param>
  975. /// <returns></returns>
  976. public static async Task<int> GetWorkDays(string yearMonth)
  977. {
  978. int workdays = 0;
  979. string sql = string.Format(@"Select * From Pm_WageIssueWorkingDay
  980. Where Isdel = 0 And YearMonth = '{0}' ", yearMonth);
  981. var data = await _usersRep._sqlSugar.SqlQueryable<WageYearMonthView>(sql).FirstAsync();
  982. if (data != null)
  983. {
  984. workdays = data.Workdays;
  985. }
  986. return workdays;
  987. }
  988. }
  989. }