PayrollComputation.cs 135 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416
  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.Drawing;
  17. using System.Linq.Expressions;
  18. using System.Text.Json.Nodes;
  19. using TencentCloud.Ocr.V20181119.Models;
  20. namespace OASystem.API.OAMethodLib
  21. {
  22. /// <summary>
  23. /// 工资计算
  24. /// </summary>
  25. public static class PayrollComputation
  26. {
  27. private static Result _result = new Result();
  28. private static readonly IQiYeWeChatApiService _qiYeWeChatApiService = AutofacIocManager.Instance.GetService<IQiYeWeChatApiService>();
  29. private static readonly UsersRepository _usersRep = AutofacIocManager.Instance.GetService<UsersRepository>();
  30. private static readonly IMapper _mapper = AutofacIocManager.Instance.GetService<IMapper>();
  31. private static readonly decimal _chengDuMinimumWage = 2100.00M * 0.80M; //员工在病假医疗期限内的病假工资按照成都市最低工资标准的 80%发放
  32. /// <summary>
  33. /// 计算工资
  34. /// </summary>
  35. /// <param name="pm_WageSheetDattaSources"></param>
  36. /// <param name="userNames"></param>
  37. /// <param name="thisYearMonth"></param>
  38. /// <param name="startDt"></param>
  39. /// <param name="endDt"></param>
  40. /// <returns></returns>
  41. public static async Task<Result> SalaryCalculatorAsync(
  42. List<Pm_WageSheet> pm_WageSheetDattaSources, List<UserNameView> userNames, int userId, string thisYearMonth, DateTime startDt, DateTime endDt)
  43. {
  44. if (pm_WageSheetDattaSources.Count <= 0)
  45. {
  46. _result.Msg = "计算工资传入数据为空!";
  47. return _result;
  48. }
  49. //计算时间段内工作日
  50. int work_days = await GetWorkDays(thisYearMonth);
  51. if (work_days <=0)
  52. {
  53. _result.Msg = $"{thisYearMonth} 工作日未设置,请前往《工作日管理页面》设置!";
  54. return _result;
  55. }
  56. UserIdListView userIdListView = await _qiYeWeChatApiService.GetUserIdListAsync();
  57. if (userIdListView.errcode != 0)
  58. {
  59. _result.Msg = $"【企业微信】【打卡】【获取员工ID】【Msg】{userIdListView.errmsg}";
  60. return _result;
  61. }
  62. //Task<QYWX_UserInfosView> GetUserInfosAsync()
  63. //QYWX_UserInfosView usersView = await _qiYeWeChatApiService.GetUserInfosAsync();
  64. //if (usersView.errcode != 0)
  65. //{
  66. // _result.Msg = $"【企业微信】【打卡】【获取员工基础信息】【Msg】{userIdListView.errmsg}";
  67. // return _result;
  68. //}
  69. List<string> qyWhchatIdList = new List<string>();
  70. qyWhchatIdList = userIdListView.dept_user.Select(it => it.userid).ToList();
  71. CheckInDayDataView checkInDayDataView = await _qiYeWeChatApiService.GetCheckInDayDataAsync(qyWhchatIdList, startDt, endDt);
  72. if (checkInDayDataView.errcode != 0)
  73. {
  74. _result.Msg = $"【企业微信】【打卡】【获取时间段内所有日打卡】【Msg】{checkInDayDataView.errmsg}";
  75. return _result;
  76. }
  77. //获取所有打卡记录 外出
  78. CheckInDataView checkInDataView = new CheckInDataView();
  79. checkInDataView = await _qiYeWeChatApiService.GetCheckinDataAsync(qyWhchatIdList, 3,startDt, endDt);
  80. if (checkInDataView.errcode != 0)
  81. {
  82. _result.Msg = $"【企业微信】【打卡】【获取时间段内所有日打卡记录】【Msg】{checkInDataView.errmsg}";
  83. return _result;
  84. }
  85. //查询工作日
  86. List<Sys_Calendar> sys_Calendars = new List<Sys_Calendar>();
  87. string sys_sql = string.Format("Select * From Sys_Calendar Where Isdel = 0 And Dt between '{0}' And '{1}'",
  88. startDt.ToString("yyyy-MM-dd"), endDt.ToString("yyyy-MM-dd"));
  89. sys_Calendars = await _usersRep._sqlSugar.SqlQueryable<Sys_Calendar>(sys_sql).ToListAsync();
  90. //筛选出工作日日报
  91. List<Root> workday_userRoots = checkInDayDataView.datas.Where(it => it.base_info.day_type == 0 && it.base_info.record_type == 1).ToList();
  92. //工作日日报
  93. workday_userRoots = workday_userRoots.OrderBy(it => it.base_info.date).ToList();
  94. #region 特殊日期-不用打卡日期信息
  95. //获取企业打卡规则
  96. CorpCheckInRuleView corpCheckInRole = await _qiYeWeChatApiService.GetCheckIn_CorpCheckInOptionAsync();
  97. if (corpCheckInRole.errcode != 0)
  98. {
  99. _result.Msg = $"【企业微信】【打卡】【获取企业打卡规则】【Msg】{corpCheckInRole.errmsg}" ;
  100. return _result;
  101. }
  102. int spe_offdays = 0;
  103. GroupItem group = corpCheckInRole.group.Where(it => it.groupid == 4).FirstOrDefault();
  104. if (group != null)
  105. {
  106. foreach (var item in group.spe_offdays)
  107. {
  108. if (item.begtime_dt>= startDt && item.endtime_dt <= endDt)
  109. {
  110. if (item.endtime_dt > startDt)
  111. {
  112. TimeSpan ts = item.endtime_dt - item.begtime_dt;
  113. spe_offdays = (ts.Days + 1);
  114. }
  115. }
  116. }
  117. }
  118. #endregion
  119. //获取 请假类型 Sp_Detail.template_id
  120. string leave_template_id = "C4NzTJCh1onCUK915rRkvy7Fh5Vqz4YbiEV9jrBY1";
  121. List<VacationLeaveTypeView> vacationLeaveTypes = await GetVacationLeaveTypes(leave_template_id);
  122. if (vacationLeaveTypes.Count <= 0)
  123. {
  124. _result.Msg = $"【企业微信】【审批】【获取审批类型】【Msg】{startDt} - {endDt}请假 类型数据 获取失败!";
  125. return _result;
  126. }
  127. string _name = "";
  128. try
  129. {
  130. #region 手动配置企业员工userid,通过userid 去匹配打卡数据
  131. //Dictionary<string, string> wx_useridDic = new Dictionary<string, string>();
  132. //wx_useridDic.Add("张海麟", "fred.chang@pan-american-intl.com");
  133. //wx_useridDic.Add("罗诗怡", "lsyyyy");
  134. //wx_useridDic.Add("赖红燕", "LaiHongYan");
  135. //wx_useridDic.Add("刘一茹", "liuyiru");
  136. //wx_useridDic.Add("李雯琪", "LiWenQi");
  137. //wx_useridDic.Add("罗聪惠", "LuoCongHui");
  138. //wx_useridDic.Add("肖俊杰", "20230410");
  139. //wx_useridDic.Add("朱成梅", "amy.zhu@pan-american-intl.com");
  140. //wx_useridDic.Add("伏虹瑾", "FuHongJin");
  141. //wx_useridDic.Add("曾艳", "judy.zeng@pan-american-intl.com");
  142. //wx_useridDic.Add("舒庆", "cilina.shu@pan-american-intl.com");
  143. //wx_useridDic.Add("高媛媛", "GaoYuanYuan");
  144. //wx_useridDic.Add("龙畑恬", "longtiantian");
  145. //wx_useridDic.Add("叶琪琪", "YeQiQi");
  146. //wx_useridDic.Add("王鸽", "ellisa.wang@pan-american-intl.com");
  147. //wx_useridDic.Add("赵雅琪", "ZhaoYaQi");
  148. //wx_useridDic.Add("陈思帆", "ChenSiFan");
  149. //wx_useridDic.Add("廖文雅", "LiaoWenYa");
  150. //wx_useridDic.Add("李敏", "annie.li@pan-american-intl.com");
  151. //wx_useridDic.Add("李明华", "LiMingHua");
  152. //wx_useridDic.Add("李文婷", "LiWenTing");
  153. //wx_useridDic.Add("仇久龙", "rf");
  154. //wx_useridDic.Add("宋夏雨", "songxiayu");
  155. //wx_useridDic.Add("王思雨", "ysw");
  156. //wx_useridDic.Add("汪燕平", "yime");
  157. //wx_useridDic.Add("张海麟", "fred.chang@pan-american-intl.com");
  158. //wx_useridDic.Add("张海麟", "fred.chang@pan-american-intl.com");
  159. //wx_useridDic.Add("张海麟", "fred.chang@pan-american-intl.com");
  160. //wx_useridDic.Add("张海麟", "fred.chang@pan-american-intl.com");
  161. //wx_useridDic.Add("张海麟", "fred.chang@pan-american-intl.com");
  162. //wx_useridDic.Add("张海麟", "fred.chang@pan-american-intl.com");
  163. //wx_useridDic.Add("张海麟", "fred.chang@pan-american-intl.com");
  164. //wx_useridDic.Add("张海麟", "fred.chang@pan-american-intl.com");
  165. //wx_useridDic.Add("张海麟", "fred.chang@pan-american-intl.com");
  166. //wx_useridDic.Add("张海麟", "fred.chang@pan-american-intl.com");
  167. //wx_useridDic.Add("张海麟", "fred.chang@pan-american-intl.com");
  168. //wx_useridDic.Add("张海麟", "fred.chang@pan-american-intl.com");
  169. //wx_useridDic.Add("张海麟", "fred.chang@pan-american-intl.com");
  170. #endregion
  171. foreach (var pm_wsInfo in pm_WageSheetDattaSources)
  172. {
  173. _name = userNames.Find(it => it.Id == pm_wsInfo.UserId)?.CnName ?? "Unknown";
  174. //补贴 金额
  175. decimal meal_subsidy = 0.00M; // 午餐(午餐10元/天) 补贴 * 计算方式:单日上午请假时长(小时)大于或者等于三小时 没有餐补
  176. //事假 病假 总金额
  177. decimal personalLeaveTotal = 0.00M, // 事假 日薪 *计算方式:日平均工资 = 月工资/当月应出勤天数。
  178. sickLeaveTotal = 0.00M; // 病假 日薪 *计算方式:日平均工资 = 成都市最低工资标准的80%/当月应出勤天数。 短期病假=当月15天内
  179. //扣款金额
  180. decimal beLate_deduction = 0.00M, // 迟到 扣款金额 *计算方式:
  181. // 一个自然月内,不足 10 分钟的迟到/早退,不超过 2 次的部分,不做处罚;3 次及以上,按50元 / 次处罚;
  182. // 超过 10 分钟(含 10 分钟),不足 60 分钟的迟到/早退,按 50 元/次处罚;
  183. // 超过 60 分钟(含 60 分钟),不足 3 小时的迟到/早退,且无请假者,按旷工半日处理;超过3 小时的迟到 / 早退,且无请假者,按旷工一日处理。
  184. early_deduction = 0.00M, // 早退 扣款金额
  185. absenteeism_deduction = 0.00M, // 旷工 扣款金额 *计算方式:旷工扣发当日工资
  186. unprinted_deduction = 0.00M, // 未打卡 扣款金额 *计算方式:
  187. // 试用期员工每月有 2 次 补卡机会,超过 2 次不足 5 次的部分,按 10 元 / 次处罚,5 次及以上的漏卡,按 50 元 / 次处罚;
  188. // 正式员工每月 3 次以内的补卡,按 10 元 / 次处罚,3 次及以上的漏卡,按 50 元 / 次处罚。
  189. sickLeave_deduction = 0.00M, // 病假
  190. other_deduction = 0.00M; // 其他 扣款金额
  191. decimal meal_deduction = 0.00M; // 餐补 扣款金额
  192. decimal reissuecard_deduction = 0.00M; // 补卡 扣款金额
  193. #region 计算日工资 正常日薪 事假日薪 病假日薪
  194. //月 - 应发工资
  195. decimal amountPayable = pm_wsInfo.Basic + pm_wsInfo.Floats + pm_wsInfo.PostAllowance + pm_wsInfo.InformationSecurityFee +
  196. pm_wsInfo.OtherSubsidies;
  197. // 日薪 = *计算方式:日平均工资 = 月工资/当月应出勤天数。
  198. decimal dailyWage = amountPayable / work_days;
  199. // 病假日薪 *计算方式:日平均工资 = 成都市最低工资标准的80%/当月应出勤天数。 短期病假=当月15天内
  200. decimal sickLeave_dailywage = _chengDuMinimumWage / work_days;
  201. //病假 一天扣款
  202. sickLeave_deduction = dailyWage - sickLeave_dailywage;
  203. List<Ex_Items> ex_Items = new List<Ex_Items>();//假勤 And 打卡备注集合
  204. Ex_Items ex_Items_dk = new Ex_Items() { Type = "打卡" }; //打卡
  205. Ex_Items ex_Items_jq = new Ex_Items() { Type = "假勤" }; //假勤
  206. Ex_Items ex_Items_cc = new Ex_Items() { Type = "出差" }; //出差
  207. #endregion
  208. List<Root> userRoots = new List<Root>();
  209. string wx_userid = "";
  210. if (_name == "蔡雯")
  211. {
  212. userRoots = workday_userRoots.Where(it => it.base_info.name == "蔡蔡" || it.base_info.name == "蔡雯").ToList(); //工作日日报 1-固定上下班;
  213. }
  214. else
  215. {
  216. userRoots = workday_userRoots.Where(it => it.base_info.name == _name || it.base_info.name.Contains(_name)).ToList(); //工作日日报 1-固定上下班;
  217. }
  218. //userRoots = userRoots.Distinct().ToList();
  219. userRoots = userRoots.OrderBy(it => it.base_info.date).ToList();
  220. int dk_work_days = userRoots.Count; //应出勤天数
  221. if (dk_work_days > work_days)
  222. {
  223. dk_work_days = work_days;
  224. }
  225. meal_subsidy = dk_work_days * 10; //应发放餐补
  226. if (!_name.Equals("张海麟"))
  227. {
  228. if (userRoots.Count <= 0)
  229. {
  230. _result.Msg = $"【{_name}】【企业微信】【打卡】【获取打卡数据】【Msg】{startDt} - {endDt} 打卡日数据 获取失败!";
  231. continue;
  232. }
  233. string acctid = userRoots[0].base_info.acctid;
  234. List<Ex_Item> ex_reissuecard_Items = new List<Ex_Item>(); //打卡类型 数据
  235. List<Sp_items> acc_sp_items = new List<Sp_items>(); //审批数据
  236. int user_probationary_bk_num = 0;
  237. decimal user_probationary_bk_decimal = pm_wsInfo.Floats; //绩效工资为0 则为试用员工
  238. //处理外出打卡记录
  239. List<CheckInDataInfo> checkInData1 = new List<CheckInDataInfo>();
  240. checkInData1 = checkInDataView.checkindata;
  241. List<CheckInDataInfo> checkInDatas = new List<CheckInDataInfo>();
  242. checkInDatas = checkInData1.Where(it => it.userid == acctid).ToList();
  243. //找出外出的打卡记录
  244. List<CheckInDataInfo> checkInData2 = new List<CheckInDataInfo>();
  245. checkInData2 = checkInDatas.Where(it => it.exception_type.Equals("未打卡")).ToList();
  246. //外出打卡
  247. List<CheckInDataInfo> checkInData_outPunch = new List<CheckInDataInfo>();
  248. checkInData_outPunch = checkInDatas.Where(it => it.checkin_type.Equals("外出打卡")).ToList();
  249. #region 迟到 早退 旷工
  250. int user_cd_zt_num = 0; //早退/迟到 次数 10分钟内 2次以内不记处罚 三次及以上50一次
  251. foreach (var root in userRoots)
  252. {
  253. List<Holiday_infos> holiday_Infos = root.holiday_infos; //当天假勤信息
  254. List<Exception_infos> exception_infos = root.exception_infos; //当天校准状态信息
  255. List<Sp_items> sp_Items = root.sp_items;//当天假勤统计信息
  256. if (sp_Items.Count > 0)
  257. {
  258. sp_Items = sp_Items.Where(it => it.count > 0).ToList();
  259. acc_sp_items.AddRange(sp_Items);
  260. }
  261. foreach (var exception_info in exception_infos)
  262. {
  263. decimal timelength = ConvertToDecimal((Convert.ToDecimal(exception_info.duration) / 3600.00M) * 60.00M); //时长 分钟
  264. if (timelength == 9) timelength = 7.50M;
  265. int exception = exception_info.exception; //异常类型
  266. decimal day_miner_unit = dailyWage / 15; //以0.5小时为单位
  267. //1:一个自然月内,不足 10 分钟的迟到/早退,不超过 2 次的部分,不做处罚;3 次及以上,按50 元 / 次处罚;
  268. //2:超过 10 分钟(含 10 分钟),不足 60 分钟的迟到 / 早退,按 50 元 / 次处罚;
  269. //3:超过 60 分钟(含 60 分钟),不足 3 小时的迟到 / 早退,且无请假者,按旷工半日处理;超过 3 小时的迟到 / 早退,且无请假者,按旷工一日处理。
  270. long date = root.base_info.date; //当日工作日期
  271. long earliest_time = root.summary_info.earliest_time; //最早打卡时间
  272. long lastest_time = root.summary_info.lastest_time; //最晚打卡时间
  273. long this_date = date + earliest_time;
  274. DateTime thisDt = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)).AddTicks(this_date * 10000000);
  275. string thisDtStr = thisDt.ToString("yyyy-MM-dd");
  276. Ex_Item beLate_belate_ex = new Ex_Item()
  277. {
  278. SubTypeId = 4,
  279. SubType = "旷工",
  280. Duration = timelength,
  281. StartTimeDt = Convert.ToDateTime(root.base_info.dateDt.ToString("yyyy-MM-dd HH:mm:ss")),
  282. Unit = "分钟",
  283. };
  284. decimal day_deduction = 0.00M;
  285. //1 - 迟到;2 - 早退;3 - 缺卡;4 - 旷工;5 - 地点异常;6 - 设备异常
  286. if (exception == 1) //迟到
  287. {
  288. if (timelength < 10)
  289. {
  290. user_cd_zt_num++;
  291. beLate_belate_ex.SubTypeId = 1;
  292. beLate_belate_ex.SubType = "迟到";
  293. string thisStartDt = (TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)).AddTicks((date + earliest_time) * 10000000))
  294. .ToString("yyyy-MM-dd HH:mm:ss");
  295. beLate_belate_ex.StartTimeDt = Convert.ToDateTime(thisStartDt);
  296. if (user_cd_zt_num >= 3)
  297. {
  298. day_deduction = 50.00M;
  299. }
  300. else
  301. {
  302. day_deduction = 0.00M;
  303. }
  304. beLate_deduction += day_deduction; //迟到扣款 总额
  305. }
  306. else if (timelength >= 10 && timelength < 60)
  307. {
  308. string thisStartDt = (TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1))
  309. .AddTicks((date + earliest_time) * 10000000))
  310. .ToString("yyyy-MM-dd HH:mm:ss");
  311. beLate_belate_ex.StartTimeDt = Convert.ToDateTime(thisStartDt);
  312. day_deduction = 50.00M;
  313. beLate_deduction += day_deduction; //迟到扣款 总额
  314. beLate_belate_ex.SubTypeId = 1;
  315. beLate_belate_ex.SubType = "迟到";
  316. }
  317. else if (timelength >= 60 && timelength <= 180)
  318. {
  319. day_deduction = ConvertToDecimal(dailyWage / 2); //3小时 按半天计算
  320. meal_deduction += 10.00M; //餐补扣款
  321. absenteeism_deduction += day_deduction; //矿工半日
  322. beLate_belate_ex.Reason = thisDtStr + " 上午(09:00)缺卡/未打卡视为旷工半天";
  323. }
  324. else
  325. {
  326. day_deduction = ConvertToDecimal(dailyWage);
  327. absenteeism_deduction += day_deduction; //矿工一日
  328. meal_deduction += 10.00M;
  329. beLate_belate_ex.Reason = thisDtStr + " 上午(09:00)-下午(18:00) 缺卡/未打视为旷工一天(7.5小时)";
  330. }
  331. beLate_belate_ex.Deduction = day_deduction;
  332. ex_reissuecard_Items.Add(beLate_belate_ex);
  333. }
  334. else if (exception == 2) //早退
  335. {
  336. if (timelength < 10)
  337. {
  338. user_cd_zt_num++;
  339. beLate_belate_ex.SubTypeId = 2;
  340. beLate_belate_ex.SubType = "早退";
  341. string thisEndDt = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1))
  342. .AddTicks((date + lastest_time) * 10000000)
  343. .ToString("yyyy-MM-dd HH:mm:ss");
  344. beLate_belate_ex.StartTimeDt = Convert.ToDateTime(thisEndDt);
  345. if (user_cd_zt_num >= 3)
  346. {
  347. day_deduction = 50.00M;
  348. }
  349. else
  350. {
  351. day_deduction = 0.00M;
  352. }
  353. early_deduction += day_deduction; //早退扣款 总计
  354. }
  355. else if (timelength >= 10 && timelength < 60)
  356. {
  357. day_deduction = 50.00M;
  358. early_deduction += day_deduction; //早退扣款 总计
  359. beLate_belate_ex.SubTypeId = 2;
  360. beLate_belate_ex.SubType = "早退";
  361. string thisEndDt = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1))
  362. .AddTicks((date + lastest_time) * 10000000)
  363. .ToString("yyyy-MM-dd HH:mm:ss");
  364. beLate_belate_ex.StartTimeDt = Convert.ToDateTime(thisEndDt);
  365. }
  366. else if (timelength >= 60 && timelength <= 180)
  367. {
  368. day_deduction = ConvertToDecimal(dailyWage / 2); //3小时 按半天计算
  369. meal_deduction += 10.00M;
  370. absenteeism_deduction += day_deduction; //矿工半日
  371. }
  372. else
  373. {
  374. day_deduction = ConvertToDecimal(dailyWage);
  375. meal_deduction += 10.00M;
  376. absenteeism_deduction += day_deduction; //矿工一日
  377. }
  378. beLate_belate_ex.Deduction = day_deduction;
  379. ex_reissuecard_Items.Add(beLate_belate_ex);
  380. }
  381. else if (exception == 3) //缺卡
  382. {
  383. if (root.exception_infos.Count == 2)
  384. {
  385. if (ex_reissuecard_Items.Where(it => it.StartTimeDt.ToString("yyyy-MM-dd").Equals(thisDtStr)).Count() > 0)
  386. {
  387. if (earliest_time == lastest_time)
  388. {
  389. DateTime thisDt1 = Convert.ToDateTime(thisDtStr + " 12:00");
  390. if (thisDt >= thisDt1) //旷工 下午
  391. {
  392. day_deduction = ConvertToDecimal(dailyWage / 2); //4.5小时 按半天计算
  393. meal_deduction += 10.00M;
  394. beLate_belate_ex.Duration = 270;
  395. absenteeism_deduction += day_deduction; //矿工半日
  396. beLate_belate_ex.Reason = thisDtStr + " 下午(18:00)缺卡/未打卡视为旷工半天";
  397. beLate_belate_ex.Deduction = day_deduction;
  398. ex_reissuecard_Items.Add(beLate_belate_ex);
  399. }
  400. else if (thisDt <= thisDt1) //旷工 上午
  401. {
  402. day_deduction = ConvertToDecimal(dailyWage / 2); //3小时 按半天计算
  403. meal_deduction += 10.00M;
  404. absenteeism_deduction += day_deduction; //矿工半日
  405. beLate_belate_ex.Duration = 180;
  406. beLate_belate_ex.Reason = thisDtStr + " 上午(09:00)缺卡/未打卡视为旷工半天";
  407. beLate_belate_ex.Deduction = day_deduction;
  408. ex_reissuecard_Items.Add(beLate_belate_ex);
  409. }
  410. else //矿工一日
  411. {
  412. day_deduction = ConvertToDecimal(dailyWage);
  413. meal_deduction += 10.00M;
  414. absenteeism_deduction += day_deduction;
  415. beLate_belate_ex.Reason = thisDtStr + " 上午(09:00)-下午(18:00) 缺卡/未打视为旷工一天(7.5小时)";
  416. beLate_belate_ex.Deduction = day_deduction;
  417. ex_reissuecard_Items.Add(beLate_belate_ex);
  418. }
  419. }
  420. }
  421. else
  422. {
  423. day_deduction = dailyWage;
  424. meal_deduction += 10.00M;
  425. absenteeism_deduction += day_deduction;
  426. beLate_belate_ex.Reason = "上午-下午 缺卡/未打卡为旷工一天";
  427. beLate_belate_ex.Deduction = day_deduction;
  428. ex_reissuecard_Items.Add(beLate_belate_ex);
  429. }
  430. }
  431. else if (root.exception_infos.Count == 1)
  432. {
  433. if (earliest_time == lastest_time)
  434. {
  435. DateTime thisDt1 = Convert.ToDateTime(thisDtStr + " 12:00");
  436. if (thisDt <= thisDt1) //旷工 下午
  437. {
  438. day_deduction = ConvertToDecimal(dailyWage / 2); //4.5小时
  439. meal_deduction += 10.00M;
  440. beLate_belate_ex.Duration = 270;
  441. absenteeism_deduction += day_deduction; //矿工半日
  442. beLate_belate_ex.Reason = thisDtStr + " 下午(18:00)缺卡/未打卡视为下午旷工(4.5小时)";
  443. beLate_belate_ex.Deduction = day_deduction;
  444. ex_reissuecard_Items.Add(beLate_belate_ex);
  445. }
  446. else if (thisDt >= thisDt1) //旷工 上午
  447. {
  448. day_deduction = ConvertToDecimal(dailyWage / 2); //3小时
  449. meal_deduction += 10.00M;
  450. absenteeism_deduction += day_deduction; //矿工半日
  451. beLate_belate_ex.Duration = 180;
  452. beLate_belate_ex.Reason = thisDtStr + " 上午(09:00)缺卡/未打卡视为上午旷工(3小时)";
  453. beLate_belate_ex.Deduction = day_deduction;
  454. ex_reissuecard_Items.Add(beLate_belate_ex);
  455. }
  456. else //矿工一日
  457. {
  458. day_deduction = ConvertToDecimal(dailyWage);
  459. meal_deduction += 10.00M;
  460. absenteeism_deduction += day_deduction;
  461. beLate_belate_ex.Reason = thisDtStr + " 上午(09:00)-下午(18:00) 缺卡/未打视为旷工一天(7.5小时)";
  462. beLate_belate_ex.Deduction = day_deduction;
  463. ex_reissuecard_Items.Add(beLate_belate_ex);
  464. }
  465. }
  466. }
  467. }
  468. else if (exception == 4) //旷工
  469. {
  470. if (timelength >= 60 && timelength <= 180)
  471. {
  472. day_deduction = ConvertToDecimal(dailyWage / 2); //3小时
  473. beLate_belate_ex.Reason = thisDtStr + " 缺卡/未打视为旷工半天";
  474. meal_deduction += 10.00M;
  475. absenteeism_deduction += day_deduction; //矿工半日
  476. }
  477. else if (timelength > 180 && timelength <= 270)
  478. {
  479. day_deduction = ConvertToDecimal(dailyWage / 2); //3小时
  480. beLate_belate_ex.Reason = thisDtStr + " 缺卡/未打视为旷工半天";
  481. meal_deduction += 10.00M;
  482. absenteeism_deduction += day_deduction; //矿工半日
  483. }
  484. else
  485. {
  486. day_deduction = ConvertToDecimal(dailyWage);
  487. beLate_belate_ex.Reason = thisDtStr + " 上午(09:00)-下午(18:00) 缺卡/未打视为旷工一天(7.5小时)";
  488. meal_deduction += 10.00M;
  489. absenteeism_deduction += day_deduction; //矿工一日
  490. }
  491. beLate_belate_ex.Deduction = day_deduction;
  492. ex_reissuecard_Items.Add(beLate_belate_ex);
  493. }
  494. }
  495. }
  496. #endregion
  497. #region 外出打卡 迟到 早退 旷工
  498. if (checkInData_outPunch.Count > 0)
  499. {
  500. List<Sp_Detail> sp_gooutpunch_details = new List<Sp_Detail>();
  501. sp_gooutpunch_details = await _qiYeWeChatApiService.GetApprovalDetailsAsync(startDt, endDt, acctid, 2, 4); //时间段内所有 已同意的 外出打卡 审批数据
  502. if (sp_gooutpunch_details.Count <= 0)
  503. {
  504. _result.Msg += $"{_name}:{startDt} - {endDt} 外出打卡 审批数据获取未获取到!\r\n";
  505. }
  506. List<LeaveDetails> goOutPunchDetails = new List<LeaveDetails>();
  507. foreach (Sp_Detail sp_item in sp_gooutpunch_details)
  508. {
  509. Apply_data? apply_data = sp_item.apply_data;
  510. if (apply_data != null)
  511. {
  512. List<ContentsItem> contents = apply_data.contents;
  513. ContentsItem content_Attendance = contents.Where(it => it.control == "Attendance").FirstOrDefault(); //请假类型
  514. ContentsItem content_Textarea = contents.Where(it => it.control == "Textarea").FirstOrDefault(); //多行文本
  515. if (content_Attendance != null)
  516. {
  517. Attendance attendance = content_Attendance.value.attendance; //假勤组件
  518. string goOutText = string.Empty;
  519. if (content_Textarea!=null)
  520. {
  521. goOutText = content_Textarea.value.text;
  522. }
  523. Date_range date_Range = attendance.date_range;
  524. //筛选 不在工作日内的假勤申请
  525. if (Convert.ToDateTime(date_Range.new_begin_dt) < startDt || Convert.ToDateTime(date_Range.new_end_dt.ToString("yyyy-MM-dd")) > endDt)
  526. {
  527. continue;
  528. }
  529. LeaveDetails leaveDetails1 = new LeaveDetails()
  530. {
  531. TypeId = 0,
  532. TypeName = "外出打卡",
  533. StartDt = date_Range.new_begin_dt,
  534. EndDt = date_Range.new_end_dt,
  535. DtType = date_Range.type,
  536. New_Duration = date_Range.new_duration
  537. };
  538. goOutPunchDetails.Add(leaveDetails1);
  539. }
  540. }
  541. }
  542. foreach (var goOutPunchItem in goOutPunchDetails)
  543. {
  544. string thisDay = goOutPunchItem.StartDt.ToString("yyyy-MM-dd");
  545. TimeSpan sp_gooutpunchStartTime = goOutPunchItem.StartDt.TimeOfDay;
  546. TimeSpan sp_gooutpunchEndTime = goOutPunchItem.EndDt.TimeOfDay;
  547. List<CheckInDataInfo> goOut_checkInDataInfos = checkInData_outPunch.Where(it => it.checkin_time_dt.ToString("yyyy-MM-dd").Equals(thisDay)).ToList();
  548. //单天
  549. if (goOut_checkInDataInfos.Count > 1)
  550. {
  551. DateTime gooutStartDt = goOut_checkInDataInfos[0].checkin_time_dt;
  552. DateTime gooutendDt = goOut_checkInDataInfos[goOut_checkInDataInfos.Count-1].checkin_time_dt;
  553. Ex_Item beLate_belate_ex = new Ex_Item()
  554. {
  555. SubTypeId = 4,
  556. SubType = "旷工",
  557. Duration = 0,
  558. StartTimeDt = Convert.ToDateTime(goOutPunchItem.StartDt),
  559. Unit = "分钟",
  560. Reason ="数据来源【外出打卡】"
  561. };
  562. decimal day_deduction = 0.00M;
  563. //迟到
  564. if (gooutStartDt.TimeOfDay > sp_gooutpunchStartTime)
  565. {
  566. int timeLong = gooutStartDt.Subtract(goOutPunchItem.StartDt).Minutes;
  567. beLate_belate_ex.Duration = timeLong;
  568. if (timeLong > 0 && timeLong < 10)
  569. {
  570. user_cd_zt_num++;
  571. beLate_belate_ex.SubTypeId = 1;
  572. beLate_belate_ex.SubType = "迟到";
  573. if (user_cd_zt_num >= 3)
  574. {
  575. day_deduction = 50.00M;
  576. }
  577. else
  578. {
  579. day_deduction = 0.00M;
  580. }
  581. beLate_deduction += day_deduction; //迟到扣款 总额
  582. }
  583. else if (timeLong >= 10 && timeLong < 60)
  584. {
  585. day_deduction = 50.00M;
  586. beLate_deduction += day_deduction; //迟到扣款 总额
  587. beLate_belate_ex.SubTypeId = 1;
  588. beLate_belate_ex.SubType = "迟到";
  589. }
  590. else if (timeLong >= 60 && timeLong <= 180)
  591. {
  592. day_deduction = ConvertToDecimal(dailyWage / 2); //3小时 按半天计算
  593. meal_deduction += 10.00M; //餐补扣款
  594. absenteeism_deduction += day_deduction; //矿工半日
  595. beLate_belate_ex.Reason = "数据来源【外出打卡】" + thisDay + " 上午(09:00)缺卡/未打卡视为旷工半天";
  596. }
  597. else
  598. {
  599. day_deduction = ConvertToDecimal(dailyWage);
  600. absenteeism_deduction += day_deduction; //矿工一日
  601. meal_deduction += 10.00M;
  602. beLate_belate_ex.Reason = "数据来源【外出打卡】" +thisDay + " 上午(09:00)-下午(18:00) 缺卡/未打视为旷工一天(7.5小时)";
  603. }
  604. beLate_belate_ex.Deduction = day_deduction;
  605. ex_reissuecard_Items.Add(beLate_belate_ex);
  606. }
  607. //早退
  608. if (gooutendDt.TimeOfDay < sp_gooutpunchEndTime)
  609. {
  610. int timeLong = goOutPunchItem.EndDt.Subtract(gooutendDt).Minutes;
  611. beLate_belate_ex.Duration = timeLong;
  612. if (timeLong > 0 && timeLong < 10)
  613. {
  614. user_cd_zt_num++;
  615. beLate_belate_ex.SubTypeId = 1;
  616. beLate_belate_ex.SubType = "早退";
  617. if (user_cd_zt_num >= 3)
  618. {
  619. day_deduction = 50.00M;
  620. }
  621. else
  622. {
  623. day_deduction = 0.00M;
  624. }
  625. early_deduction += day_deduction; //迟到扣款 总额
  626. }
  627. else if (timeLong >= 10 && timeLong < 60)
  628. {
  629. day_deduction = 50.00M;
  630. early_deduction += day_deduction; //迟到扣款 总额
  631. beLate_belate_ex.SubTypeId = 1;
  632. beLate_belate_ex.SubType = "早退";
  633. }
  634. else if (timeLong >= 60 && timeLong <= 180)
  635. {
  636. day_deduction = ConvertToDecimal(dailyWage / 2); //3小时 按半天计算
  637. meal_deduction += 10.00M; //餐补扣款
  638. absenteeism_deduction += day_deduction; //矿工半日
  639. beLate_belate_ex.Reason = "数据来源【外出打卡】" + thisDay + " 上午(09:00)缺卡/未打卡视为旷工半天";
  640. }
  641. else
  642. {
  643. day_deduction = ConvertToDecimal(dailyWage);
  644. absenteeism_deduction += day_deduction; //矿工一日
  645. meal_deduction += 10.00M;
  646. beLate_belate_ex.Reason = "数据来源【外出打卡】" + thisDay + " 上午(09:00)-下午(18:00) 缺卡/未打视为旷工一天(7.5小时)";
  647. }
  648. beLate_belate_ex.Deduction = day_deduction;
  649. ex_reissuecard_Items.Add(beLate_belate_ex);
  650. }
  651. }
  652. //多天
  653. }
  654. }
  655. #endregion
  656. #region 迟到早团旷工 日期排序
  657. if (ex_reissuecard_Items.Count > 0)
  658. {
  659. ex_reissuecard_Items = ex_reissuecard_Items.OrderBy(it => it.StartTimeDt).ToList();
  660. }
  661. #endregion
  662. #region 假勤/补卡次数 审批
  663. int leaveNum = 0; //请假次数
  664. int reissuecardNum = 0; //补卡次数
  665. int evectionNum = 0; //出差次数
  666. //类型:1 - 请假;2 - 补卡;3 - 出差;4 - 外出;100 - 外勤
  667. leaveNum = acc_sp_items.Where(it => it.type == 1).ToList().Count();
  668. reissuecardNum = acc_sp_items.Where(it => it.type == 2).ToList().Count();
  669. List<Sp_items> acc_sp_items_evection = new List<Sp_items>();
  670. acc_sp_items_evection = acc_sp_items.Where(it => it.type == 3).ToList();
  671. evectionNum = acc_sp_items_evection.Count();
  672. //请假审批
  673. if (leaveNum > 0)
  674. {
  675. List<Sp_Detail> sp_leave_details = new List<Sp_Detail>();
  676. sp_leave_details = await _qiYeWeChatApiService.GetApprovalDetailsAsync(startDt, endDt, acctid, 2, 1); //时间段内所有 已同意的 请假 审批数据
  677. if (sp_leave_details.Count <= 0)
  678. {
  679. _result.Msg += $"{_name}: {startDt} - {endDt} 请假 审批数据获取未获取到!\r\n";
  680. //continue;
  681. }
  682. List<Ex_Item> ex_ItemInfos = new List<Ex_Item>();
  683. List<LeaveDetails> leaveDetails = new List<LeaveDetails>();
  684. foreach (Sp_Detail sp_item in sp_leave_details)
  685. {
  686. Apply_data? apply_data = sp_item.apply_data;
  687. if (apply_data != null)
  688. {
  689. List<ContentsItem> contents = apply_data.contents;
  690. ContentsItem content_Vacation = contents.Where(it => it.control == "Vacation").FirstOrDefault(); //请假类型
  691. ContentsItem content_Textarea = contents.Where(it => it.control == "Textarea").FirstOrDefault(); //多行文本
  692. if (content_Vacation != null)
  693. {
  694. Vacation vacation = content_Vacation.value.vacation;
  695. Attendance attendance = vacation.attendance; //假勤组件
  696. Selector selector = vacation.selector; //请假类型
  697. List<OptionsItem> optionsItems = selector.options; //key 请假类型 id
  698. List<TitleItem> value = optionsItems[0].value; // value 文本描述值
  699. int leaveType = int.Parse(optionsItems[0].key); //key 请假子类型 id
  700. Date_range date_Range = attendance.date_range;
  701. //筛选 不在工作日内的假勤申请
  702. //if (Convert.ToDateTime(date_Range.new_begin_dt) < startDt || Convert.ToDateTime(date_Range.new_end_dt.ToString("yyyy-MM-dd")) > endDt)
  703. //{
  704. // continue;
  705. //}
  706. //假期只要开始时间,结束时间在计算时间范围 即纳入计算
  707. if ((Convert.ToDateTime(date_Range.new_begin_dt) < startDt || Convert.ToDateTime(date_Range.new_begin_dt) > endDt) &&
  708. (Convert.ToDateTime(date_Range.new_end_dt) < startDt || Convert.ToDateTime(date_Range.new_end_dt) > endDt))
  709. {
  710. continue;
  711. }
  712. string leave_starttime = date_Range.new_begin_dt.ToString("HH:mm");
  713. string leave_endtime = date_Range.new_end_dt.ToString("HH:mm");
  714. string typeName = string.Empty;
  715. string unit = string.Empty;
  716. int leaveTypeId = leaveType;
  717. var leaveTypeData = vacationLeaveTypes.Where(it => it.id == leaveTypeId).FirstOrDefault();
  718. if (leaveTypeData != null) { typeName = leaveTypeData.name; }
  719. string startTime = string.Empty;
  720. string endTime = string.Empty;
  721. string startTime1 = string.Empty;
  722. string endTime1 = string.Empty;
  723. Slice_info slice_info = new Slice_info();
  724. //2事假;3病假;
  725. if (leaveTypeId == 2 || leaveTypeId ==3)
  726. {
  727. slice_info = vacation.attendance.slice_info;
  728. }
  729. DateTime date_Range_new_begin_dt = date_Range.new_begin_dt;
  730. DateTime date_Range_new_end_dt = date_Range.new_end_dt;
  731. //计算请假类型扣款金额
  732. decimal new_duration = 0.00M;
  733. if (date_Range.type == "halfday")
  734. {
  735. new_duration = Convert.ToDecimal(date_Range.new_duration) / 86400.00M;
  736. if (date_Range.new_begin_dt < startDt)
  737. {
  738. decimal new_duration_count = new_duration;
  739. new_duration = 0.00M;
  740. for (int i = 0; i < new_duration_count; i++)
  741. {
  742. DateTime thisDt = date_Range.new_begin_dt.AddDays(i);
  743. Sys_Calendar sys_Calendar = new Sys_Calendar();
  744. sys_Calendar = sys_Calendars.Where(it => it.Dt == thisDt.ToString("yyyy-MM-dd")).FirstOrDefault();
  745. if (sys_Calendar != null)
  746. {
  747. if (sys_Calendar.IsWorkDay)
  748. {
  749. new_duration++;
  750. }
  751. }
  752. }
  753. }
  754. unit = "天";
  755. startTime = date_Range_new_begin_dt.ToString("yyyy-MM-dd") + " 09:00";
  756. endTime = date_Range_new_end_dt.ToString("yyyy-MM-dd") + " 18:00";
  757. if (new_duration > 0.50M)
  758. {
  759. if (slice_info != null)
  760. {
  761. if (slice_info.day_items != null)
  762. {
  763. if (slice_info.day_items.Count > 1)
  764. {
  765. date_Range_new_begin_dt = slice_info.day_items[0].daytimeDt;
  766. date_Range_new_end_dt = slice_info.day_items[slice_info.day_items.Count - 1].daytimeDt;
  767. decimal startTime11 = slice_info.day_items[0].duration;
  768. decimal startTime11_11 = startTime11 / 3600.00M;
  769. decimal endTime11 = slice_info.day_items[slice_info.day_items.Count - 1].duration;
  770. decimal endTime11_11 = endTime11 / 3600.00M;
  771. if (startTime11_11 == 3.00M)
  772. {
  773. startTime1 = "09:00";
  774. }
  775. else if (startTime11_11 == 4.50M)
  776. {
  777. startTime1 = "12:00";
  778. }
  779. else if (startTime11_11 == 7.50M)
  780. {
  781. startTime1 = "09:00";
  782. }
  783. if (endTime11_11 == 3.00M)
  784. {
  785. endTime1 = "12:00";
  786. }
  787. else if (endTime11_11 == 4.50M)
  788. {
  789. endTime1 = "18:00";
  790. }
  791. else if (endTime11_11 == 7.50M)
  792. {
  793. endTime1 = "18:00";
  794. }
  795. }
  796. else
  797. {
  798. decimal qjLongTime = slice_info.duration / 3600.00M;
  799. if (qjLongTime == 4.50M)
  800. {
  801. startTime1 = "12:00";
  802. endTime1 = "18:00:00";
  803. }
  804. else if (qjLongTime == 3.00M)
  805. {
  806. startTime1 = "09:00";
  807. endTime1 = "12:00:00";
  808. }
  809. else if (qjLongTime % 7.50M == 0)
  810. {
  811. startTime1 = "09:00";
  812. endTime1 = "18:00:00";
  813. }
  814. }
  815. }
  816. else
  817. {
  818. if (new_duration % 1 == 0)
  819. {
  820. startTime1 = "09:00";
  821. endTime1 = "18:00";
  822. }
  823. }
  824. }
  825. else
  826. {
  827. if (new_duration % 1 == 0)
  828. {
  829. startTime1 = "09:00";
  830. endTime1 = "18:00";
  831. }
  832. }
  833. }
  834. else
  835. {
  836. if (new_duration % 1 == 0)
  837. {
  838. startTime1 = "09:00";
  839. endTime1 = "18:00";
  840. }
  841. else
  842. {
  843. startTime1 = date_Range_new_begin_dt.ToString("HH:mm:ss");
  844. endTime1 = date_Range_new_end_dt.ToString("HH:mm:ss");
  845. }
  846. }
  847. }
  848. else if (date_Range.type == "hour")
  849. {
  850. new_duration = Convert.ToDecimal(date_Range.new_duration) / 3600.00M;
  851. unit = "小时";
  852. startTime = date_Range_new_begin_dt.ToString("yyyy-MM-dd HH:mm:ss");
  853. endTime = date_Range_new_end_dt.ToString("yyyy-MM-dd HH:mm:ss");
  854. startTime1 = date_Range_new_begin_dt.ToString("HH:mm:ss");
  855. endTime1 = date_Range_new_end_dt.ToString("HH:mm:ss");
  856. }
  857. LeaveDetails leaveDetails1 = new LeaveDetails()
  858. {
  859. TypeId = leaveType,
  860. TypeName = typeName,
  861. StartDt = Convert.ToDateTime(date_Range_new_begin_dt.ToString("yyyy-MM-dd") + " " + startTime1),
  862. EndDt = Convert.ToDateTime(date_Range_new_end_dt.ToString("yyyy-MM-dd") + " " + endTime1),
  863. DtType = date_Range.type,
  864. Unit = unit,
  865. New_Duration = new_duration,
  866. SliceInfo = slice_info
  867. };
  868. leaveDetails.Add(leaveDetails1);
  869. }
  870. }
  871. }
  872. #region 年假测试数据
  873. //leaveDetails.Add(new LeaveDetails() {
  874. // TypeId = 1,
  875. // TypeName = "年假",
  876. // StartDt = Convert.ToDateTime("2023-11-21 09:00:00"),
  877. // EndDt = Convert.ToDateTime("2023-11-21 12:00:00"),
  878. // DtType = "halfday",
  879. // Unit = "天",
  880. // New_Duration = 0.50M
  881. //});
  882. //leaveDetails.Add(new LeaveDetails()
  883. //{
  884. // TypeId = 1,
  885. // TypeName = "年假",
  886. // StartDt = Convert.ToDateTime("2023-11-21 12:00:00"),
  887. // EndDt = Convert.ToDateTime("2023-11-23 18:00:00"),
  888. // DtType = "halfday",
  889. // Unit = "天",
  890. // New_Duration = 2.50M
  891. //});
  892. #endregion
  893. if (leaveDetails.Count > 0)
  894. {
  895. leaveDetails = leaveDetails.OrderBy(it => it.StartDt).OrderBy(it => it.EndDt).ToList();
  896. foreach (LeaveDetails leave_item in leaveDetails)
  897. {
  898. decimal leave_meals = 0.00M;
  899. decimal thisTypeDeduction = 0.00M;//当前类型扣款
  900. int leaveType = leave_item.TypeId;
  901. decimal new_duration = leave_item.New_Duration;
  902. #region 处理跨月天数
  903. if (leave_item.EndDt > endDt)
  904. {
  905. DateTime dt1 = Convert.ToDateTime(leave_item.StartDt.ToString("yyyy-MM-dd") + " 12:00");
  906. DateTime dt2 = Convert.ToDateTime(leave_item.StartDt.ToString("yyyy-MM-dd") + " 09:00");
  907. TimeSpan ts = Convert.ToDateTime(endDt.ToString("yyyy-MM-dd") + " 18:00") - Convert.ToDateTime(leave_item.StartDt.ToString("yyyy-MM-dd"));
  908. if (dt2 >= leave_item.StartDt && leave_item.StartDt <= dt1)
  909. {
  910. new_duration = ts.Days + 1;
  911. }
  912. else
  913. {
  914. new_duration = ts.Days + 1.00M + 0.50M;
  915. }
  916. }
  917. #endregion
  918. //计算餐补 假勤类型扣款
  919. CalculateTypeFee1(leaveDetails,leaveType, leave_item.DtType, leave_item.StartDt, leave_item.EndDt, amountPayable, work_days,
  920. new_duration,out leave_meals, out thisTypeDeduction);
  921. if (leave_meals != 0)
  922. {
  923. leave_item.IsDeduction = true;
  924. }
  925. #region 累计类型扣款
  926. //1年假;2事假;3病假;4调休假;5婚假;6产假;7陪产假;8其他;9丧假
  927. if (leaveType == 2) //事假
  928. {
  929. personalLeaveTotal += thisTypeDeduction;
  930. }
  931. else if (leaveType == 3) //病假
  932. {
  933. sickLeaveTotal += thisTypeDeduction;
  934. }
  935. #endregion
  936. meal_deduction += leave_meals;
  937. Ex_Item ex_Item = new Ex_Item()
  938. {
  939. SubTypeId = leaveType,
  940. SubType = leave_item.TypeName,
  941. StartTimeDt = leave_item.StartDt,
  942. EndTimeDt = leave_item.EndDt,
  943. Duration = new_duration,
  944. Unit = leave_item.Unit,
  945. Deduction = thisTypeDeduction,
  946. //Reason = apply_data.reason,
  947. Apply_time_dt = leave_item.ApplyDt,
  948. //Approval_name = sp_item.approval_name,
  949. };
  950. ex_ItemInfos.Add(ex_Item);
  951. }
  952. }
  953. if (ex_ItemInfos.Count > 0)
  954. {
  955. ex_Items_jq.Ex_ItemInfo = ex_ItemInfos.OrderBy(it => it.StartTimeDt).ThenBy(it => it.Apply_time_dt).ToList();
  956. ex_Items.Add(ex_Items_jq);
  957. }
  958. }
  959. //打卡补卡
  960. //补卡:员工发现自己漏打卡时,需及时提起补卡申请,并说明情况。
  961. //试用期员工每月有 2 次补卡机会,超过 2 次不足 5 次的部分,按 10 元/次处罚,5 次及以上的漏卡,按 50 元/次处罚;
  962. //正式员工每月 3 次以内的补卡,按 10 元/次处罚,3 次及以上的漏卡,按 50 元/次处罚。
  963. if (reissuecardNum > 0)
  964. {
  965. List<Sp_Detail> sp_buka_details = new List<Sp_Detail>();
  966. sp_buka_details = await _qiYeWeChatApiService.GetApprovalDetailsAsync(startDt, endDt, acctid, 2, 2); //时间段内所有 已同意的 请假 审批数据
  967. //外出审批 已通过的数据 且 外出未打卡
  968. List<Sp_Detail> sp_goout_details = new List<Sp_Detail>();
  969. sp_goout_details = await _qiYeWeChatApiService.GetApprovalDetailsAsync(startDt, endDt, acctid, 2, 4); //时间段内所有 已同意的 外出 审批数据
  970. //打卡记录-未打卡 处理日期范围内的数据
  971. List<CheckInDataInfo> filtratePrefix_checkInData = new List<CheckInDataInfo>();
  972. //打卡记录-未打卡 扣款
  973. if (sp_goout_details.Count > 0)
  974. {
  975. //找出外出的具体日期
  976. List<string> goOutDts = new List<string>();
  977. foreach (var goOutItem in sp_goout_details)
  978. {
  979. Apply_data? apply_data = goOutItem.apply_data;
  980. if (apply_data != null)
  981. {
  982. List<ContentsItem> contents = apply_data.contents;
  983. ContentsItem content_Vacation = contents.Where(it => it.control == "Attendance").FirstOrDefault(); //请假类型
  984. ContentsItem content_Textarea = contents.Where(it => it.control == "Textarea").FirstOrDefault(); //多行文本
  985. if (content_Vacation != null)
  986. {
  987. var attendance = content_Vacation.value.attendance;
  988. DateTime goOutDt = attendance.date_range.new_begin_dt;
  989. DateTime goOutDtJudge = Convert.ToDateTime(goOutDt.ToString("yyyy-MM-dd"));
  990. //筛选 不在工作日内的假勤申请
  991. if (startDt >= goOutDtJudge || goOutDtJudge > endDt)
  992. {
  993. continue;
  994. }
  995. goOutDts.Add(goOutDt.ToString("yyyy-MM-dd"));
  996. }
  997. }
  998. }
  999. if (goOutDts.Count > 0)
  1000. {
  1001. foreach (var goOutDtItem in goOutDts)
  1002. {
  1003. List<CheckInDataInfo> filtrate_checkInData = new List<CheckInDataInfo>();
  1004. filtrate_checkInData = checkInData2.Where(it => it.checkin_time_dt.ToString("yyyy-MM-dd").Equals(goOutDtItem)).ToList();
  1005. if (filtrate_checkInData.Count > 0)
  1006. {
  1007. filtratePrefix_checkInData.AddRange(filtrate_checkInData);
  1008. }
  1009. }
  1010. }
  1011. }
  1012. int bukaNum = 1;
  1013. foreach (var item in sp_buka_details)
  1014. {
  1015. Apply_data? apply_data = item.apply_data;
  1016. if (apply_data != null)
  1017. {
  1018. List<ContentsItem> contents = apply_data.contents;
  1019. ContentsItem content_Vacation = contents.Where(it => it.control == "PunchCorrection").FirstOrDefault(); //请假类型
  1020. ContentsItem content_Textarea = contents.Where(it => it.control == "Textarea").FirstOrDefault(); //多行文本
  1021. if (content_Vacation != null)
  1022. {
  1023. var punch_correction = content_Vacation.value.punch_correction;
  1024. DateTime bukaDt = punch_correction.time_dt;
  1025. DateTime bukaDtJudge = Convert.ToDateTime(bukaDt.ToString("yyyy-MM-dd"));
  1026. //筛选 不在工作日内的假勤申请
  1027. if (startDt > bukaDtJudge || bukaDtJudge > endDt)
  1028. {
  1029. continue;
  1030. }
  1031. decimal bukaPrice = 0.00M;
  1032. if (user_probationary_bk_decimal == 0) //计算试用员工补卡次数
  1033. {
  1034. if (bukaNum <= 2) bukaPrice = 0.00M;
  1035. else if (bukaNum <= 4 && bukaNum > 2) bukaPrice = 10.00M;
  1036. else bukaPrice = 50.00M;
  1037. }
  1038. else //计算正式员工补卡次数
  1039. {
  1040. if (bukaNum <= 2) bukaPrice = 10.00M;
  1041. else bukaPrice = 50.00M;
  1042. }
  1043. var app_data = item.apply_data;
  1044. var punch_correction1 = app_data.contents[0].value.punch_correction; //未打卡时间
  1045. var punch_correction2 = app_data.contents[1].value;
  1046. #region 处理未打卡记录表数据 已补卡的数据
  1047. if (filtratePrefix_checkInData.Count > 0)
  1048. {
  1049. var filtratePrefix_checkInItems = filtratePrefix_checkInData.Where(it => it.sch_checkin_time_dt.ToString("yyyy-MM-dd")
  1050. .Equals(punch_correction1.time_dt.ToString("yyyy-MM-dd"))).ToList();
  1051. if (filtratePrefix_checkInItems.Count > 0)
  1052. {
  1053. //按时间段移除 上午补卡时间段 09:00 - 12:00 下午补卡时间段 12:00 - 18:00
  1054. TimeSpan _strWorkingDayAM = DateTime.Parse("09:00").TimeOfDay;
  1055. TimeSpan _endWorkingDayAM = DateTime.Parse("12:00").TimeOfDay;
  1056. TimeSpan _strWorkingDayPM = DateTime.Parse("13:30").TimeOfDay;
  1057. TimeSpan _endWorkingDayPM = DateTime.Parse("18:00").TimeOfDay;
  1058. TimeSpan _dspNow = punch_correction1.time_dt.TimeOfDay;
  1059. //上午时间段 打卡记录数据
  1060. var filtratePrefix_checkInItemAMs = filtratePrefix_checkInItems.Where(it => it.sch_checkin_time_dt.TimeOfDay >= _strWorkingDayAM &&
  1061. it.sch_checkin_time_dt.TimeOfDay <= _endWorkingDayAM ).ToList();
  1062. if (filtratePrefix_checkInItemAMs.Count > 0)
  1063. {
  1064. foreach (var filtratePrefix_checkInItem1 in filtratePrefix_checkInItemAMs)
  1065. {
  1066. filtratePrefix_checkInData.Remove(filtratePrefix_checkInItem1);
  1067. }
  1068. }
  1069. //下午时间段 打卡记录数据
  1070. var filtratePrefix_checkInItemPMs = filtratePrefix_checkInItems.Where(it => it.sch_checkin_time_dt.TimeOfDay >= _strWorkingDayPM &&
  1071. it.sch_checkin_time_dt.TimeOfDay <= _endWorkingDayPM).ToList();
  1072. if (filtratePrefix_checkInItemPMs.Count > 0)
  1073. {
  1074. foreach (var filtratePrefix_checkInItem1 in filtratePrefix_checkInItemPMs)
  1075. {
  1076. filtratePrefix_checkInData.Remove(filtratePrefix_checkInItem1);
  1077. }
  1078. }
  1079. }
  1080. }
  1081. #endregion
  1082. Ex_Item ex_reissueCard = new Ex_Item()
  1083. {
  1084. SubTypeId = 7,
  1085. SubType = "打卡补卡",
  1086. StartTimeDt = Convert.ToDateTime(punch_correction1.time_dt.ToString("yyyy-MM-dd HH:mm:ss")), //未打卡时间
  1087. Deduction = bukaPrice,
  1088. Reason = punch_correction2.text,
  1089. Unit = string.Empty
  1090. };
  1091. unprinted_deduction += bukaPrice;
  1092. ex_reissuecard_Items.Add(ex_reissueCard);
  1093. bukaNum++;
  1094. }
  1095. }
  1096. }
  1097. //打卡记录里抓取的未打卡数据 扣款
  1098. foreach (var item in filtratePrefix_checkInData)
  1099. {
  1100. decimal bukaPrice = 0.00M;
  1101. if (user_probationary_bk_decimal == 0) //计算试用员工补卡次数
  1102. {
  1103. if (bukaNum <= 2) bukaPrice = 0.00M;
  1104. else if (bukaNum <= 4 && bukaNum > 2) bukaPrice = 10.00M;
  1105. else bukaPrice = 50.00M;
  1106. }
  1107. else //计算正式员工补卡次数
  1108. {
  1109. if (bukaNum <= 2) bukaPrice = 10.00M;
  1110. else bukaPrice = 50.00M;
  1111. }
  1112. Ex_Item ex_reissueCard = new Ex_Item()
  1113. {
  1114. SubTypeId = 7,
  1115. SubType = "打卡补卡",
  1116. StartTimeDt = Convert.ToDateTime(item.checkin_time_dt.ToString("yyyy-MM-dd HH:mm:ss")), //未打卡时间
  1117. Deduction = bukaPrice,
  1118. Reason = "[打卡记录]抓取到的未打卡数据!",
  1119. Unit = string.Empty
  1120. };
  1121. unprinted_deduction += bukaPrice;
  1122. ex_reissuecard_Items.Add(ex_reissueCard);
  1123. bukaNum++;
  1124. }
  1125. }
  1126. if (ex_reissuecard_Items.Count > 0)
  1127. {
  1128. ex_Items_dk.Ex_ItemInfo = ex_reissuecard_Items;
  1129. ex_Items_dk.Ex_ItemInfo = ex_reissuecard_Items.OrderBy(it => it.SubTypeId).ThenBy(it => it.StartTimeDt).ToList();
  1130. ex_Items.Add(ex_Items_dk);
  1131. }
  1132. //出差申请
  1133. if (evectionNum > 0)
  1134. {
  1135. List<Sp_Detail> sp_leave_details = new List<Sp_Detail>();
  1136. sp_leave_details = await _qiYeWeChatApiService.GetApprovalDetailsAsync(startDt, endDt, acctid, 2, 3); //时间段内所有 已同意的 出差 审批数据
  1137. if (sp_leave_details.Count <= 0)
  1138. {
  1139. _result.Msg += $"{_name}: {startDt} - {endDt} 请假 审批数据获取未获取到!\r\n";
  1140. //continue;
  1141. }
  1142. List<Ex_Item> cc_ex_ItemInfos = new List<Ex_Item>();
  1143. foreach (Sp_Detail sp_item in sp_leave_details)
  1144. {
  1145. Apply_data? apply_data = sp_item.apply_data;
  1146. if (apply_data != null)
  1147. {
  1148. List<ContentsItem> contents = apply_data.contents;
  1149. ContentsItem content_Vacation = contents.Where(it => it.control == "Attendance").FirstOrDefault(); //出差类型
  1150. ContentsItem content_Textarea = contents.Where(it => it.control == "Textarea").FirstOrDefault(); //多行文本
  1151. if (content_Vacation != null)
  1152. {
  1153. //Vacation vacation = content_Vacation.value.vacation;
  1154. Attendance attendance = content_Vacation.value.attendance; //假勤组件
  1155. //Selector selector = vacation.selector; //请假类型
  1156. //List<OptionsItem> optionsItems = selector.options; //key 请假类型 id
  1157. //List<TitleItem> value = optionsItems[0].value; // value 文本描述值
  1158. int leaveType = int.Parse("3"); //key 请假子类型 id
  1159. Date_range date_Range = attendance.date_range;
  1160. //筛选 不在工作日内的假勤申请
  1161. if (date_Range.new_begin_dt < startDt || date_Range.new_end_dt > endDt)
  1162. {
  1163. continue;
  1164. }
  1165. string leave_starttime = date_Range.new_begin_dt.ToString("HH:mm");
  1166. string leave_endtime = date_Range.new_end_dt.ToString("HH:mm");
  1167. string typeName = string.Empty;
  1168. string unit = string.Empty;
  1169. int leaveTypeId = leaveType;
  1170. typeName = "出差";
  1171. string startTime = string.Empty;
  1172. string endTime = string.Empty;
  1173. string startTime1 = string.Empty;
  1174. string endTime1 = string.Empty;
  1175. //计算请假类型扣款金额
  1176. decimal new_duration = 0.00M;
  1177. if (date_Range.type == "halfday")
  1178. {
  1179. new_duration = Convert.ToDecimal(date_Range.new_duration) / 86400.00M;
  1180. unit = "天";
  1181. startTime = date_Range.new_begin_dt.ToString("yyyy-MM-dd") + " 00:00";
  1182. endTime = date_Range.new_end_dt.ToString("yyyy-MM-dd") + " 00:00";
  1183. startTime1 = "00:00:00";
  1184. endTime1 = "00:00:00";
  1185. }
  1186. else if (date_Range.type == "hour")
  1187. {
  1188. new_duration = Convert.ToDecimal(date_Range.new_duration) / 3600.00M;
  1189. unit = "小时";
  1190. startTime = date_Range.new_begin_dt.ToString("yyyy-MM-dd HH:mm:ss");
  1191. endTime = date_Range.new_end_dt.ToString("yyyy-MM-dd HH:mm:ss");
  1192. startTime1 = date_Range.new_begin_dt.ToString("HH:mm:ss");
  1193. endTime1 = date_Range.new_end_dt.ToString("HH:mm:ss");
  1194. }
  1195. //出差扣款
  1196. decimal cckk = 0.00M;
  1197. int days = (int)(Convert.ToDateTime(date_Range.new_end_dt.ToString("yyyy-MM-dd")) -
  1198. Convert.ToDateTime(date_Range.new_begin_dt.ToString("yyyy-MM-dd"))).TotalDays + 1;
  1199. for (int i = 0; i < days; i++)
  1200. {
  1201. DateTime thisDt = date_Range.new_begin_dt.AddDays(i);
  1202. //处理开始时间 是否在当天工作时间内
  1203. if (i == 0) //开始时间
  1204. {
  1205. if (!date_Range.type.Equals("halfday"))
  1206. {
  1207. string ccStartTime = thisDt.ToString("HH:mm:ss");
  1208. if (!IsWorkTime(ccStartTime))
  1209. {
  1210. continue;
  1211. }
  1212. }
  1213. }
  1214. //处理结束时间 是否在当天工作时间内
  1215. if (i == days - 1)
  1216. {
  1217. if (!date_Range.type.Equals("halfday"))
  1218. {
  1219. string ccStartTime = date_Range.new_end_dt.ToString("HH:mm:ss");
  1220. if (!IsWorkTime(ccStartTime))
  1221. {
  1222. continue;
  1223. }
  1224. }
  1225. }
  1226. Sys_Calendar sys_Calendar = new Sys_Calendar();
  1227. sys_Calendar = sys_Calendars.Where(it => it.Dt == thisDt.ToString("yyyy-MM-dd")).FirstOrDefault();
  1228. if (sys_Calendar != null) {
  1229. if (sys_Calendar.IsWorkDay)
  1230. {
  1231. cckk += 10.00M;
  1232. }
  1233. }
  1234. }
  1235. meal_deduction += cckk;
  1236. Ex_Item ex_Item = new Ex_Item()
  1237. {
  1238. SubTypeId = leaveType,
  1239. SubType = typeName,
  1240. StartTimeDt = Convert.ToDateTime(date_Range.new_begin_dt.ToString("yyyy-MM-dd") + " " + startTime1),
  1241. EndTimeDt = Convert.ToDateTime(date_Range.new_end_dt.ToString("yyyy-MM-dd") + " " + endTime1),
  1242. Duration = new_duration,
  1243. Unit = unit,
  1244. Deduction = 0.00M,
  1245. //Reason = apply_data.reason,
  1246. Apply_time_dt = Convert.ToDateTime(sp_item.apply_time_dt.ToString("yyyy-MM-dd HH:mm:ss"))
  1247. //Approval_name = sp_item.approval_name,
  1248. };
  1249. cc_ex_ItemInfos.Add(ex_Item);
  1250. }
  1251. }
  1252. }
  1253. if (cc_ex_ItemInfos.Count > 0)
  1254. {
  1255. //ex_Items_cc.Ex_ItemInfo = cc_ex_ItemInfos.OrderBy(it => it.StartTimeDt).ThenBy(it => it.Apply_time_dt).ToList();
  1256. //;
  1257. //ex_Items.Add(ex_Items_cc);
  1258. List<Ex_Item> ex_jq_Items = new List<Ex_Item>();
  1259. List<Ex_Item> ex_Items1 = new List<Ex_Item>();
  1260. ex_Items1 = (List<Ex_Item>)ex_Items_jq.Ex_ItemInfo;
  1261. if (ex_Items1 != null && ex_Items1.Count > 0)
  1262. {
  1263. ex_jq_Items = ex_Items1;
  1264. }
  1265. ex_jq_Items.AddRange(cc_ex_ItemInfos);
  1266. ex_Items.Remove(ex_Items_jq);
  1267. ex_Items.Add(
  1268. new Ex_Items()
  1269. {
  1270. Type = "假勤",
  1271. Ex_ItemInfo = ex_jq_Items.OrderBy(it => it.StartTimeDt).ThenBy(it => it.Apply_time_dt).ToList()
  1272. }
  1273. );
  1274. }
  1275. }
  1276. #endregion
  1277. }
  1278. else
  1279. {
  1280. meal_subsidy = work_days * 10.00M;
  1281. }
  1282. #region 应发合计 实发合计 扣款合计(假勤扣款,其他扣款,社保扣款,公积金代扣,个税扣款)
  1283. int workDays = dk_work_days + spe_offdays;
  1284. decimal mealTotal = meal_subsidy - meal_deduction; //餐补
  1285. decimal salaryTotal = 0.00M;
  1286. if (dk_work_days >= work_days)
  1287. {
  1288. dk_work_days = work_days;
  1289. salaryTotal = amountPayable + mealTotal + pm_wsInfo.OtherHandle; //应发合计
  1290. }
  1291. else
  1292. {
  1293. if (_name.Equals("张海麟"))
  1294. {
  1295. salaryTotal = amountPayable + mealTotal + pm_wsInfo.OtherHandle; //应发合计
  1296. }
  1297. else
  1298. {
  1299. salaryTotal = (workDays * dailyWage) + mealTotal + pm_wsInfo.OtherHandle; //应发合计
  1300. }
  1301. }
  1302. //扣款合计 不含个税
  1303. decimal eductionTotal = sickLeaveTotal + personalLeaveTotal + beLate_deduction + early_deduction + absenteeism_deduction + unprinted_deduction + other_deduction +
  1304. pm_wsInfo.WithholdingInsurance + pm_wsInfo.ReservedFunds + pm_wsInfo.OtherDeductions;
  1305. decimal actualReleaseTotal = salaryTotal - eductionTotal; //实发合计 * 不含个税
  1306. #endregion
  1307. #region 处理当月工资数据
  1308. pm_wsInfo.YearMonth = thisYearMonth;
  1309. pm_wsInfo.StartDate = startDt.ToString("yyyy-MM-dd");
  1310. pm_wsInfo.EndDate = endDt.ToString("yyyy-MM-dd");
  1311. pm_wsInfo.WorkDays = work_days; //当月应出勤天数
  1312. pm_wsInfo.RegularDays = workDays; //当月正常出勤天数
  1313. pm_wsInfo.SickLeave = sickLeaveTotal; //病假
  1314. pm_wsInfo.SomethingFalse = personalLeaveTotal; //事假
  1315. pm_wsInfo.LateTo = beLate_deduction; //迟到
  1316. pm_wsInfo.LeaveEarly = early_deduction; //早退
  1317. pm_wsInfo.Absenteeism = absenteeism_deduction; //旷工
  1318. pm_wsInfo.NotPunch = unprinted_deduction; //未打卡
  1319. pm_wsInfo.OtherDeductions = other_deduction; //其他
  1320. pm_wsInfo.Ex_ItemsRemark = JsonConvert.SerializeObject(ex_Items); //
  1321. pm_wsInfo.Mealsupplement = mealTotal; //餐补
  1322. pm_wsInfo.Should = ConvertToDecimal( salaryTotal); //应发合计
  1323. pm_wsInfo.TotalDeductions = ConvertToDecimal(eductionTotal); //扣款合计
  1324. pm_wsInfo.TotalRealHair = ConvertToDecimal(actualReleaseTotal - pm_wsInfo.WithholdingTax); //实发合计
  1325. pm_wsInfo.AfterTax = ConvertToDecimal(actualReleaseTotal - pm_wsInfo.WithholdingTax); //税后工资
  1326. pm_wsInfo.LastUpdateUserId = userId;
  1327. pm_wsInfo.LastUpdateDt = DateTime.Now;
  1328. pm_wsInfo.CreateUserId = userId;
  1329. pm_wsInfo.CreateTime = DateTime.Now;
  1330. pm_wsInfo.DeleteUserId = null;
  1331. pm_wsInfo.DeleteTime = null;
  1332. #endregion
  1333. }
  1334. }
  1335. catch (Exception ex)
  1336. {
  1337. _result.Msg = $"【{_name}】【Msg:{ex.Message}】";
  1338. return _result;
  1339. }
  1340. _result.Code = 0;
  1341. _result.Data = pm_WageSheetDattaSources;
  1342. return _result;
  1343. }
  1344. /// <summary>
  1345. /// 是否在工作时间内
  1346. /// </summary>
  1347. /// <param name="timeStr"></param>
  1348. /// <returns></returns>
  1349. public static bool IsWorkTime(string timeStr)
  1350. {
  1351. string thisDayWorkStartTime = "09:00:00";
  1352. string thisDayWorkEndTime = "18:00:00";
  1353. TimeSpan dspWorkingDayAM = DateTime.Parse(thisDayWorkStartTime).TimeOfDay;
  1354. TimeSpan dspWorkingDayPM = DateTime.Parse(thisDayWorkEndTime).TimeOfDay;
  1355. DateTime dt = Convert.ToDateTime(timeStr);
  1356. TimeSpan dspNow = dt.TimeOfDay;
  1357. if (dspNow >= dspWorkingDayAM && dspNow <= dspWorkingDayPM)
  1358. {
  1359. return true;
  1360. }
  1361. return false;
  1362. }
  1363. /// <summary>
  1364. /// decimal 保留两位小数 不四舍五入
  1365. /// </summary>
  1366. /// <param name="number"></param>
  1367. /// <returns></returns>
  1368. public static decimal ConvertToDecimal(decimal myDecimal)
  1369. {
  1370. var subDecimal = Math.Floor(myDecimal * 100) / 100;//保留两位小数,直接截取
  1371. return subDecimal;
  1372. }
  1373. /// <summary>
  1374. /// decimal 保留两位小数 不四舍五入
  1375. /// </summary>
  1376. /// <param name="number"></param>
  1377. /// <returns></returns>
  1378. public static decimal ConvertToDecimal1(this decimal myDecimal)
  1379. {
  1380. var subDecimal = Math.Floor(myDecimal * 100) / 100;//保留两位小数,直接截取
  1381. return subDecimal;
  1382. }
  1383. /// <summary>
  1384. /// 列表的成员移动到列表的前面
  1385. /// </summary>
  1386. /// <typeparam name="T"></typeparam>
  1387. /// <param name="list"></param>
  1388. /// <param name="index"></param>
  1389. public static void MoveItemAtIndexToFront<T>(this List<T> list, int index)
  1390. {
  1391. T item = list[index];
  1392. list.RemoveAt(index);
  1393. list.Insert(0, item);
  1394. }
  1395. /// <summary>
  1396. /// 获取请假类型
  1397. /// </summary>
  1398. /// <param name="template_id"></param>
  1399. /// <returns></returns>
  1400. public static async Task<List<VacationLeaveTypeView>> GetVacationLeaveTypes(string template_id)
  1401. {
  1402. List<VacationLeaveTypeView> vacationLeaveTypes = new List<VacationLeaveTypeView>();
  1403. TemplateDetailView templateDetailView = new TemplateDetailView();
  1404. templateDetailView = await _qiYeWeChatApiService.GetTemplateDetailAsync(template_id);
  1405. if (templateDetailView.errcode != 0)
  1406. {
  1407. Serilog.Log.Error("【企业微信】【审批】【获取假勤类型的审批】【Msg】"+ templateDetailView.errmsg);
  1408. return vacationLeaveTypes;
  1409. }
  1410. List<VacationItemInfo> VacationItemInfos = templateDetailView.vacation_list.item;
  1411. foreach (var item in VacationItemInfos)
  1412. {
  1413. ValueItem valueInfo = item.name.Where(it => it.lang == "zh_CN").FirstOrDefault();
  1414. if (valueInfo != null)
  1415. {
  1416. vacationLeaveTypes.Add(
  1417. new VacationLeaveTypeView()
  1418. {
  1419. id = item.id,
  1420. name = valueInfo.text
  1421. });
  1422. }
  1423. }
  1424. return vacationLeaveTypes;
  1425. }
  1426. /// <summary>
  1427. /// 计算类型费用
  1428. /// 病假 事假 计算 按天计算
  1429. /// </summary>
  1430. /// <param name="leaveType">
  1431. /// 1年假;2事假;3病假;4调休假;5婚假;6产假;7陪产假;8其他;9丧假
  1432. /// </param>
  1433. /// <param name="date_Range_type">
  1434. /// halfday 全天
  1435. /// hour 小时
  1436. /// </param>
  1437. /// <param name="startTime"></param>
  1438. /// <param name="endTime"></param>
  1439. /// <param name="duration"></param>
  1440. /// <param name="mealDeduction"></param>
  1441. /// <param name="typeDeduction"></param>
  1442. public static void CalculateTypeFee1(List<LeaveDetails> leaveDetails, int leaveType, string date_Range_type, DateTime startTime, DateTime endTime,
  1443. decimal amountPayable, int work_days, decimal duration, out decimal mealDeduction, out decimal typeDeduction)
  1444. {
  1445. typeDeduction = 0;
  1446. mealDeduction = 0;
  1447. decimal personalkLeave_dailywage_day = amountPayable / work_days; //日薪 = 事假日薪 *计算方式:日平均工资 = 当月应发工资 /当月应出勤天数。
  1448. //半小时单位
  1449. decimal halfHour = 7.50M / 0.50M;
  1450. switch (leaveType)
  1451. {
  1452. case 1: //年假
  1453. if (date_Range_type == "halfday")
  1454. {
  1455. if (duration >= 0.5M && duration <= 1M) //一天
  1456. {
  1457. var njItem = leaveDetails.Where(it => it.StartDt.ToString("yyyy-MM-dd") == startTime.ToString("yyyy-MM-dd") &&
  1458. it.EndDt.ToString("yyyy-MM-dd") == endTime.ToString("yyyy-MM-dd")).ToList();
  1459. if (njItem.Count > 1)
  1460. {
  1461. if (njItem[0].StartDt == startTime)
  1462. {
  1463. mealDeduction = 10; //餐补扣款
  1464. }
  1465. }
  1466. else
  1467. {
  1468. mealDeduction = 10; //餐补扣款
  1469. }
  1470. }
  1471. else // 多天
  1472. {
  1473. var njManyDaysItem = leaveDetails.Where(it => it.StartDt.ToString("yyyy-MM-dd") == startTime.ToString("yyyy-MM-dd")).ToList();
  1474. if (njManyDaysItem.Count > 1)
  1475. {
  1476. var njManyDaysItem1 = njManyDaysItem.Where(it => it.StartDt != startTime).ToList();
  1477. if (njManyDaysItem1.Count > 0)
  1478. {
  1479. if (njManyDaysItem1[0].Unit.Equals("天"))
  1480. {
  1481. mealDeduction = 10 * Math.Floor(duration);
  1482. }
  1483. else if (njManyDaysItem1[0].Unit.Equals("小时") && njManyDaysItem1[0].New_Duration >= 3)
  1484. {
  1485. mealDeduction = 10 * Math.Floor(duration);
  1486. }
  1487. else
  1488. {
  1489. mealDeduction = 10 * Math.Ceiling(duration);
  1490. }
  1491. }
  1492. }
  1493. else
  1494. {
  1495. mealDeduction = 10 * Math.Ceiling(duration);
  1496. }
  1497. }
  1498. }
  1499. break;
  1500. case 2: //2事假
  1501. // 事假日薪 *计算方式:日平均工资 = 当月应发工资 /当月应出勤天数。
  1502. decimal personalkLeave_dailywage_halfhour = personalkLeave_dailywage_day / 7.50M; //事假单位 0.5小时
  1503. if (date_Range_type == "halfday")
  1504. {
  1505. #region 处理当天是否扣除餐补
  1506. string formatDt_begin = startTime.ToString("yyyy-MM-dd");
  1507. List<LeaveDetails> leaveDetails1 = leaveDetails.Where(it => it.IsDeduction && it.EndDt.ToString("yyyy-MM-dd") == formatDt_begin).ToList();
  1508. if (leaveDetails1.Count > 0) mealDeduction = 10.00M * Math.Floor(duration); //餐补扣款
  1509. else mealDeduction = 10.00M * Math.Ceiling(duration); //餐补扣款
  1510. #endregion
  1511. if (duration % 1 == 0) //整天
  1512. {
  1513. typeDeduction = ConvertToDecimal(personalkLeave_dailywage_day * duration);
  1514. }
  1515. else //多含 半天 另外处理
  1516. {
  1517. decimal sj_wholeDay = Math.Floor(duration); //整天
  1518. decimal sj_halfDay = duration % 1; //半天
  1519. if (duration % 1 > 0)
  1520. {
  1521. typeDeduction = (personalkLeave_dailywage_day / 2.00M) * (duration / 0.50M);
  1522. }
  1523. else
  1524. {
  1525. typeDeduction = (personalkLeave_dailywage_day / 2.00M);
  1526. }
  1527. typeDeduction = ConvertToDecimal(typeDeduction);
  1528. }
  1529. }
  1530. else if (date_Range_type == "hour")
  1531. {
  1532. decimal leave_halfHour = Convert.ToDecimal(duration) / Convert.ToDecimal(0.5);
  1533. typeDeduction = ConvertToDecimal(personalkLeave_dailywage_halfhour * leave_halfHour);
  1534. //duration = 11M;
  1535. if (duration >= 3 && duration < 7.5M) //单天请假三小时
  1536. {
  1537. mealDeduction = 10; //餐补扣款
  1538. }
  1539. else if (duration >= 7.5M) //多天计算
  1540. {
  1541. decimal leave_halfHour1 = Convert.ToDecimal(duration) / Convert.ToDecimal(0.5);
  1542. decimal leaveDays = duration / 7.5M;
  1543. if (leaveDays % 1 == 0)
  1544. {
  1545. typeDeduction = ConvertToDecimal(personalkLeave_dailywage_day * leaveDays);
  1546. mealDeduction = 10 * leaveDays; //餐补扣款
  1547. }
  1548. else
  1549. {
  1550. typeDeduction = personalkLeave_dailywage_day * Convert.ToInt32(leaveDays);
  1551. decimal sy_shijiaunit = leave_halfHour1 - Convert.ToDecimal(15.00M * Convert.ToInt32(leaveDays));
  1552. if (sy_shijiaunit > 0)
  1553. {
  1554. typeDeduction += ConvertToDecimal(personalkLeave_dailywage_halfhour * sy_shijiaunit);
  1555. }
  1556. mealDeduction = 10 * Convert.ToInt32(leaveDays);
  1557. //得到最后一天的请假时间 是否有餐补
  1558. int lastHours = (Convert.ToDateTime(endTime) - Convert.ToDateTime("09:00")).Hours;
  1559. if (lastHours >= 3)
  1560. {
  1561. mealDeduction += 10; //餐补扣款
  1562. }
  1563. }
  1564. }
  1565. }
  1566. break;
  1567. case 3: //3病假
  1568. // 病假日薪 *计算方式:日平均工资 = 成都市最低工资标准的80% /当月应出勤天数。 短期病假=当月15天内
  1569. decimal chengDuMinimumWage_Day = _chengDuMinimumWage / work_days;
  1570. decimal chengDuMinimumWage_halrHour = chengDuMinimumWage_Day / 7.50M;
  1571. decimal sickLeave_dailywage_halfhour_deduction1 = (personalkLeave_dailywage_day / 7.50M) - chengDuMinimumWage_halrHour; //病假单位 0.5小时 扣款金额
  1572. if (date_Range_type == "halfday")
  1573. {
  1574. mealDeduction = 10.00M * Math.Ceiling(duration); //餐补扣款
  1575. decimal pl_dailywage_day = personalkLeave_dailywage_day - chengDuMinimumWage_Day;
  1576. if (duration % 1 == 0) //整天
  1577. {
  1578. typeDeduction = ConvertToDecimal(pl_dailywage_day * duration);
  1579. }
  1580. else //多含 半天 另外处理
  1581. {
  1582. #region 处理当天是否扣除餐补
  1583. string formatDt_begin = startTime.ToString("yyyy-MM-dd");
  1584. List<LeaveDetails> leaveDetails1 = leaveDetails.Where(it => it.IsDeduction && it.EndDt.ToString("yyyy-MM-dd") == formatDt_begin).ToList();
  1585. if (leaveDetails1.Count > 0) mealDeduction = 10.00M * Math.Floor(duration); //餐补扣款
  1586. else mealDeduction = 10.00M * Math.Ceiling(duration); //餐补扣款
  1587. #endregion
  1588. if (duration % 1 > 0)
  1589. {
  1590. typeDeduction = (pl_dailywage_day / 2.00M) * (duration / 0.50M); ;
  1591. }
  1592. else
  1593. {
  1594. typeDeduction = (pl_dailywage_day / 2.00M);
  1595. }
  1596. typeDeduction = ConvertToDecimal(typeDeduction);
  1597. }
  1598. }
  1599. else if (date_Range_type == "hour")
  1600. {
  1601. decimal sickLeave_halfHour = duration / 0.5M;
  1602. typeDeduction = ConvertToDecimal(sickLeave_dailywage_halfhour_deduction1 * sickLeave_halfHour);
  1603. if (duration >= 3 && duration < 7.5M) //单天请假三小时 && 请假时间在上午 则没有餐补
  1604. {
  1605. mealDeduction = 10; //餐补扣款
  1606. }
  1607. else if (duration >= 7.5M) //多天计算
  1608. {
  1609. decimal sickLeave_halfHour1 = duration / 0.5M;
  1610. decimal leaveDays = Convert.ToDecimal(duration / 7.5M);
  1611. typeDeduction = ConvertToDecimal(sickLeave_dailywage_halfhour_deduction1 * sickLeave_halfHour1);
  1612. if (leaveDays % 1 == 0)
  1613. {
  1614. mealDeduction = 10 * leaveDays; //餐补扣款
  1615. }
  1616. else
  1617. {
  1618. mealDeduction = 10 * Convert.ToInt32(leaveDays);
  1619. typeDeduction = ConvertToDecimal(sickLeave_dailywage_halfhour_deduction1 * Convert.ToInt32(leaveDays));
  1620. decimal sy_bingjiaunit = sickLeave_halfHour1 - Convert.ToDecimal(15.00M * Convert.ToInt32(leaveDays));
  1621. if (sy_bingjiaunit > 0)
  1622. {
  1623. typeDeduction += ConvertToDecimal(sickLeave_dailywage_halfhour_deduction1 * sy_bingjiaunit);
  1624. }
  1625. //得到最后一天的请假时间 是否有餐补
  1626. int lastHours = (Convert.ToDateTime(endTime) - Convert.ToDateTime("09:00")).Hours;
  1627. if (lastHours >= 3)
  1628. {
  1629. mealDeduction += 10; //餐补扣款
  1630. }
  1631. }
  1632. }
  1633. }
  1634. break;
  1635. case 4: //4调休假
  1636. CalculateTypeFeeSub(leaveDetails, date_Range_type, startTime, endTime, duration, out mealDeduction);
  1637. break;
  1638. case 5: //5婚假
  1639. CalculateTypeFeeSub(leaveDetails, date_Range_type, startTime, endTime, duration, out mealDeduction);
  1640. break;
  1641. case 6: //6产假
  1642. CalculateTypeFeeSub(leaveDetails, date_Range_type, startTime, endTime, duration, out mealDeduction);
  1643. break;
  1644. case 7: //7陪产假
  1645. CalculateTypeFeeSub(leaveDetails, date_Range_type, startTime, endTime, duration, out mealDeduction);
  1646. break;
  1647. case 8: //8其他
  1648. CalculateTypeFeeSub(leaveDetails, date_Range_type, startTime, endTime, duration, out mealDeduction);
  1649. break;
  1650. case 9: //9丧假
  1651. if (date_Range_type == "halfday")
  1652. {
  1653. if (duration >= 0.5M && duration <= 1M) //一天
  1654. {
  1655. var njItem = leaveDetails.Where(it => it.StartDt.ToString("yyyy-MM-dd") == startTime.ToString("yyyy-MM-dd") &&
  1656. it.EndDt.ToString("yyyy-MM-dd") == endTime.ToString("yyyy-MM-dd")).ToList();
  1657. if (njItem.Count > 1)
  1658. {
  1659. if (njItem[0].StartDt == startTime)
  1660. {
  1661. mealDeduction = 10; //餐补扣款
  1662. }
  1663. }
  1664. else
  1665. {
  1666. mealDeduction = 10; //餐补扣款
  1667. }
  1668. }
  1669. else // 多天
  1670. {
  1671. var njManyDaysItem = leaveDetails.Where(it => it.StartDt.ToString("yyyy-MM-dd") == startTime.ToString("yyyy-MM-dd")).ToList();
  1672. if (njManyDaysItem.Count > 1)
  1673. {
  1674. var njManyDaysItem1 = njManyDaysItem.Where(it => it.StartDt != startTime).ToList();
  1675. if (njManyDaysItem1.Count > 0)
  1676. {
  1677. if (njManyDaysItem1[0].Unit.Equals("天"))
  1678. {
  1679. mealDeduction = 10 * Math.Floor(duration);
  1680. }
  1681. else if (njManyDaysItem1[0].Unit.Equals("小时") && njManyDaysItem1[0].New_Duration >= 3)
  1682. {
  1683. mealDeduction = 10 * Math.Floor(duration);
  1684. }
  1685. else
  1686. {
  1687. mealDeduction = 10 * Math.Ceiling(duration);
  1688. }
  1689. }
  1690. }
  1691. else
  1692. {
  1693. mealDeduction = 10 * Math.Ceiling(duration);
  1694. }
  1695. }
  1696. }
  1697. break;
  1698. }
  1699. }
  1700. /// <summary>
  1701. /// 计算类型费用
  1702. /// 病假 事假 计算 按小时计算
  1703. /// </summary>
  1704. /// <param name="leaveType">
  1705. /// 1年假;2事假;3病假;4调休假;5婚假;6产假;7陪产假;8其他;9丧假
  1706. /// </param>
  1707. /// <param name="date_Range_type">
  1708. /// halfday 全天
  1709. /// hour 小时
  1710. /// </param>
  1711. /// <param name="startTime"></param>
  1712. /// <param name="endTime"></param>
  1713. /// <param name="duration"></param>
  1714. /// <param name="mealDeduction"></param>
  1715. /// <param name="typeDeduction"></param>
  1716. public static void CalculateTypeFee2(List<LeaveDetails> leaveDetails,int leaveType, string date_Range_type, DateTime startTime, DateTime endTime,
  1717. decimal amountPayable,int work_days, decimal duration, out decimal mealDeduction, out decimal typeDeduction)
  1718. {
  1719. typeDeduction = 0;
  1720. mealDeduction = 0;
  1721. string am_starttime = "08:59";
  1722. string am_endtime = "13:01";
  1723. decimal personalkLeave_dailywage_day = amountPayable / work_days; //日薪 = 事假日薪 *计算方式:日平均工资 = 当月应发工资 /当月应出勤天数。
  1724. //半小时单位
  1725. decimal halfHour = 7.50M / 0.50M;
  1726. switch (leaveType)
  1727. {
  1728. case 1: //年假
  1729. if (date_Range_type == "halfday")
  1730. {
  1731. if (duration >= 0.5M && duration <= 1M) //一天
  1732. {
  1733. var njItem = leaveDetails.Where(it => it.StartDt.ToString("yyyy-MM-dd") == startTime.ToString("yyyy-MM-dd") &&
  1734. it.EndDt.ToString("yyyy-MM-dd") == endTime.ToString("yyyy-MM-dd")).ToList();
  1735. if (njItem.Count > 1)
  1736. {
  1737. if (njItem[0].StartDt == startTime)
  1738. {
  1739. mealDeduction = 10; //餐补扣款
  1740. }
  1741. }
  1742. else
  1743. {
  1744. mealDeduction = 10; //餐补扣款
  1745. }
  1746. }
  1747. else // 多天
  1748. {
  1749. var njManyDaysItem = leaveDetails.Where(it => it.StartDt.ToString("yyyy-MM-dd") == startTime.ToString("yyyy-MM-dd")).ToList();
  1750. if (njManyDaysItem.Count > 1)
  1751. {
  1752. var njManyDaysItem1 = njManyDaysItem.Where(it => it.StartDt != startTime).ToList();
  1753. if (njManyDaysItem1.Count > 0)
  1754. {
  1755. if (njManyDaysItem1[0].Unit.Equals("天"))
  1756. {
  1757. mealDeduction = 10 * Math.Floor(duration);
  1758. }
  1759. else if (njManyDaysItem1[0].Unit.Equals("小时") && njManyDaysItem1[0].New_Duration >= 3)
  1760. {
  1761. mealDeduction = 10 * Math.Floor(duration);
  1762. }
  1763. else
  1764. {
  1765. mealDeduction = 10 * Math.Ceiling(duration);
  1766. }
  1767. }
  1768. }
  1769. else
  1770. {
  1771. mealDeduction = 10 * Math.Ceiling(duration);
  1772. }
  1773. }
  1774. }
  1775. break;
  1776. case 2: //2事假
  1777. // 事假日薪 *计算方式:日平均工资 = 当月应发工资 /当月应出勤天数。
  1778. decimal personalkLeave_dailywage_halfhour = personalkLeave_dailywage_day / 7.50M; //事假单位 0.5小时
  1779. if (date_Range_type == "halfday")
  1780. {
  1781. mealDeduction = 10.00M * Math.Floor(duration); //餐补扣款
  1782. if (duration % 1 == 0) //整天
  1783. {
  1784. typeDeduction = ConvertToDecimal(personalkLeave_dailywage_day * duration);
  1785. }
  1786. else //多含 半天 另外处理
  1787. {
  1788. decimal sj_wholeDay = Math.Floor(duration); //整天
  1789. decimal sj_halfDay = duration % 1; //半天
  1790. if (sj_halfDay > 0)
  1791. {
  1792. LeaveDetails sjDetails = leaveDetails.Where(it => it.StartDt == startTime && it.EndDt == endTime).FirstOrDefault();
  1793. decimal sjPrice = 0.00M;
  1794. if (sjDetails != null)
  1795. {
  1796. Slice_info sj_slice_Info = sjDetails.SliceInfo;
  1797. if (sj_slice_Info != null)
  1798. {
  1799. decimal sjLongTime = (sj_slice_Info.duration / 3600.00M);
  1800. typeDeduction = (personalkLeave_dailywage_day / 7.50M) * sjLongTime;
  1801. }
  1802. }
  1803. LeaveDetails sjDetailsMeal = leaveDetails.Where(it => it.EndDt == startTime ).FirstOrDefault();
  1804. if (sjDetailsMeal == null)
  1805. {
  1806. mealDeduction += 10.00M;
  1807. }
  1808. }
  1809. else
  1810. {
  1811. typeDeduction = personalkLeave_dailywage_day* sj_wholeDay;
  1812. }
  1813. typeDeduction = ConvertToDecimal(typeDeduction);
  1814. }
  1815. }
  1816. else if (date_Range_type == "hour")
  1817. {
  1818. decimal leave_halfHour = Convert.ToDecimal(duration) / Convert.ToDecimal(0.5);
  1819. typeDeduction = ConvertToDecimal(personalkLeave_dailywage_halfhour * leave_halfHour);
  1820. //duration = 11M;
  1821. if (duration >= 3 && duration < 7.5M) //单天请假三小时
  1822. {
  1823. mealDeduction = 10; //餐补扣款
  1824. }
  1825. else if (duration >= 7.5M) //多天计算
  1826. {
  1827. decimal leave_halfHour1 = Convert.ToDecimal(duration) / Convert.ToDecimal(0.5);
  1828. decimal leaveDays = duration / 7.5M;
  1829. if (leaveDays % 1 == 0)
  1830. {
  1831. typeDeduction = ConvertToDecimal(personalkLeave_dailywage_day * leaveDays);
  1832. mealDeduction = 10 * leaveDays; //餐补扣款
  1833. }
  1834. else
  1835. {
  1836. typeDeduction = personalkLeave_dailywage_day * Convert.ToInt32(leaveDays);
  1837. decimal sy_shijiaunit = leave_halfHour1 - Convert.ToDecimal (15.00M * Convert.ToInt32(leaveDays));
  1838. if (sy_shijiaunit > 0)
  1839. {
  1840. typeDeduction += ConvertToDecimal(personalkLeave_dailywage_halfhour * sy_shijiaunit);
  1841. }
  1842. mealDeduction = 10 * Convert.ToInt32(leaveDays);
  1843. //得到最后一天的请假时间 是否有餐补
  1844. int lastHours = (Convert.ToDateTime(endTime) - Convert.ToDateTime("09:00")).Hours;
  1845. if (lastHours >= 3)
  1846. {
  1847. mealDeduction += 10; //餐补扣款
  1848. }
  1849. }
  1850. }
  1851. }
  1852. break;
  1853. case 3: //3病假
  1854. // 病假日薪 *计算方式:日平均工资 = 成都市最低工资标准的80% /当月应出勤天数。 短期病假=当月15天内
  1855. decimal chengDuMinimumWage_Day = _chengDuMinimumWage / work_days;
  1856. decimal chengDuMinimumWage_halrHour = chengDuMinimumWage_Day / 7.50M;
  1857. decimal sickLeave_dailywage_halfhour_deduction1 = (personalkLeave_dailywage_day / 7.50M) - chengDuMinimumWage_halrHour; //病假单位 0.5小时 扣款金额
  1858. if (date_Range_type == "halfday")
  1859. {
  1860. mealDeduction = 10.00M * Math.Ceiling(duration); //餐补扣款
  1861. decimal pl_dailywage_day = personalkLeave_dailywage_day - chengDuMinimumWage_Day;
  1862. if (duration % 1 == 0) //整天
  1863. {
  1864. typeDeduction = ConvertToDecimal(pl_dailywage_day * duration);
  1865. }
  1866. else //多含 半天 另外处理
  1867. {
  1868. decimal bj_wholeDay = Math.Floor(duration); //整天
  1869. decimal bj_halfDay = duration % 1; //半天
  1870. decimal bj_wholeDayWage = pl_dailywage_day * bj_wholeDay;
  1871. decimal bj_halfDayWage = 0.00M;
  1872. if (bj_halfDay > 0)
  1873. {
  1874. LeaveDetails bjDetails = leaveDetails.Where(it => it.StartDt == startTime && it.EndDt == endTime).FirstOrDefault();
  1875. decimal bjPrice = 0.00M;
  1876. if (bjDetails != null)
  1877. {
  1878. Slice_info bj_slice_Info = bjDetails.SliceInfo;
  1879. decimal bjLongTime = bj_slice_Info.duration / 3600.00M;
  1880. if (bjLongTime == 3.00M)
  1881. {
  1882. bj_halfDayWage = (pl_dailywage_day / 7.50M) * 3.00M;
  1883. }
  1884. else if (bjLongTime == 4.50M)
  1885. {
  1886. bj_halfDayWage = (pl_dailywage_day / 7.50M) * 4.50M;
  1887. }
  1888. }
  1889. }
  1890. typeDeduction = ConvertToDecimal(bj_wholeDayWage + bj_halfDayWage);
  1891. }
  1892. }
  1893. else if (date_Range_type == "hour")
  1894. {
  1895. decimal sickLeave_halfHour = duration / 0.5M;
  1896. typeDeduction = ConvertToDecimal(sickLeave_dailywage_halfhour_deduction1 * sickLeave_halfHour);
  1897. if (duration >= 3 && duration < 7.5M) //单天请假三小时 && 请假时间在上午 则没有餐补
  1898. {
  1899. mealDeduction = 10; //餐补扣款
  1900. }
  1901. else if (duration >= 7.5M) //多天计算
  1902. {
  1903. decimal sickLeave_halfHour1 = duration / 0.5M;
  1904. decimal leaveDays = Convert.ToDecimal(duration / 7.5M);
  1905. typeDeduction = ConvertToDecimal(sickLeave_dailywage_halfhour_deduction1 * sickLeave_halfHour1);
  1906. if (leaveDays % 1 == 0)
  1907. {
  1908. mealDeduction = 10 * leaveDays; //餐补扣款
  1909. }
  1910. else
  1911. {
  1912. mealDeduction = 10 * Convert.ToInt32(leaveDays);
  1913. typeDeduction = ConvertToDecimal(sickLeave_dailywage_halfhour_deduction1 * Convert.ToInt32(leaveDays));
  1914. decimal sy_bingjiaunit = sickLeave_halfHour1 - Convert.ToDecimal(15.00M * Convert.ToInt32(leaveDays));
  1915. if (sy_bingjiaunit > 0)
  1916. {
  1917. typeDeduction += ConvertToDecimal(sickLeave_dailywage_halfhour_deduction1 * sy_bingjiaunit);
  1918. }
  1919. //得到最后一天的请假时间 是否有餐补
  1920. int lastHours = (Convert.ToDateTime(endTime) - Convert.ToDateTime("09:00")).Hours;
  1921. if (lastHours >= 3)
  1922. {
  1923. mealDeduction += 10; //餐补扣款
  1924. }
  1925. }
  1926. }
  1927. }
  1928. break;
  1929. case 4: //4调休假
  1930. CalculateTypeFeeSub(leaveDetails,date_Range_type, startTime, endTime, duration, out mealDeduction);
  1931. break;
  1932. case 5: //5婚假
  1933. CalculateTypeFeeSub(leaveDetails,date_Range_type, startTime, endTime, duration, out mealDeduction);
  1934. break;
  1935. case 6: //6产假
  1936. CalculateTypeFeeSub(leaveDetails,date_Range_type, startTime, endTime, duration, out mealDeduction);
  1937. break;
  1938. case 7: //7陪产假
  1939. CalculateTypeFeeSub(leaveDetails,date_Range_type, startTime, endTime, duration, out mealDeduction);
  1940. break;
  1941. case 8: //8其他
  1942. CalculateTypeFeeSub(leaveDetails,date_Range_type, startTime, endTime, duration, out mealDeduction);
  1943. break;
  1944. case 9: //9丧假
  1945. CalculateTypeFeeSub(leaveDetails,date_Range_type, startTime, endTime, duration, out mealDeduction);
  1946. break;
  1947. }
  1948. }
  1949. /// <summary>
  1950. /// 计算类型费用
  1951. /// </summary>
  1952. /// <param name="date_Range_type">
  1953. /// halfday 全天
  1954. /// hour 小时
  1955. /// </param>
  1956. /// <param name="startTime"></param>
  1957. /// <param name="endTime"></param>
  1958. /// <param name="duration"></param>
  1959. /// <param name="mealDeduction"></param>
  1960. public static void CalculateTypeFeeSub(List<LeaveDetails> leaveDetails,string date_Range_type, DateTime startTime1, DateTime endTime1,
  1961. decimal duration, out decimal mealDeduction)
  1962. {
  1963. mealDeduction = 0;
  1964. string am_starttime = "09:00";
  1965. string am_endtime = "11:59";
  1966. string startTime = startTime1.ToString("HH:mm:ss");
  1967. string endTime = endTime1.ToString("HH:mm:ss");
  1968. if (date_Range_type == "halfday")
  1969. {
  1970. mealDeduction = Math.Ceiling(duration) * 10; //餐补扣款
  1971. }
  1972. else if (date_Range_type == "hour")
  1973. {
  1974. List<LeaveDetails> leaveDetails1 = new List<LeaveDetails>();
  1975. leaveDetails1 = leaveDetails.Where(it => it.StartDt.ToString("yyyy-MM-dd").Equals(startTime1.ToString("yyyy-MM-dd")))
  1976. .OrderBy(it => it.StartDt).ToList();
  1977. if (leaveDetails1.Count > 1)
  1978. {
  1979. decimal timelenTatoal = leaveDetails1.Sum(it => it.New_Duration);
  1980. if (timelenTatoal >= 3.00M)
  1981. {
  1982. if (leaveDetails1[0].StartDt == startTime1)
  1983. {
  1984. mealDeduction = 10; //餐补扣款
  1985. }
  1986. }
  1987. }
  1988. else
  1989. {
  1990. if (duration >= 3 && duration < 7) //单天请假三小时 && 请假时间在上午 则没有餐补
  1991. {
  1992. mealDeduction = 10; //餐补扣款
  1993. }
  1994. else if (duration >= 7 && duration <= 7.50M)
  1995. {
  1996. mealDeduction = 10; //餐补扣款
  1997. }
  1998. else if (duration >= 7.50M) //多天计算
  1999. {
  2000. decimal leaveDays = Convert.ToDecimal(duration / 7.50M);
  2001. if (leaveDays % 1 == 0)
  2002. {
  2003. mealDeduction = 10 * leaveDays; //餐补扣款
  2004. }
  2005. else
  2006. {
  2007. mealDeduction = 10 * Convert.ToInt32(leaveDays);
  2008. //得到最后一天的请假时间 是否有餐补
  2009. int lastHours = (Convert.ToDateTime(endTime) - Convert.ToDateTime("09:00")).Hours;
  2010. if (lastHours >= 3)
  2011. {
  2012. mealDeduction += 10; //餐补扣款
  2013. ////处理结束时间
  2014. //if (endTime.CompareTo(am_starttime) > 0 && endTime.CompareTo(am_endtime) < 0)
  2015. //{
  2016. // mealDeduction += 10; //餐补扣款
  2017. //}
  2018. }
  2019. }
  2020. }
  2021. }
  2022. }
  2023. }
  2024. /// <summary>
  2025. /// 获取打卡补卡类型
  2026. /// </summary>
  2027. /// <param name="template_id"></param>
  2028. /// <returns></returns>
  2029. public static async Task<List<VacationLeaveTypeView>> GetVacationReissueCardTypes(string template_id)
  2030. {
  2031. List<VacationLeaveTypeView> vacationLeaveTypes = new List<VacationLeaveTypeView>();
  2032. TemplateDetailView templateDetailView = new TemplateDetailView();
  2033. templateDetailView = await _qiYeWeChatApiService.GetTemplateDetailAsync(template_id);
  2034. if (templateDetailView.errcode != 0)
  2035. {
  2036. return vacationLeaveTypes;
  2037. }
  2038. List<VacationItemInfo> VacationItemInfos = templateDetailView.vacation_list.item;
  2039. foreach (var item in VacationItemInfos)
  2040. {
  2041. ValueItem valueInfo = item.name.Where(it => it.lang == "zh_CN").FirstOrDefault();
  2042. if (valueInfo != null)
  2043. {
  2044. vacationLeaveTypes.Add(
  2045. new VacationLeaveTypeView()
  2046. {
  2047. id = item.id,
  2048. name = valueInfo.text
  2049. });
  2050. }
  2051. }
  2052. return vacationLeaveTypes;
  2053. }
  2054. /// <summary>
  2055. /// 打卡数据
  2056. /// 假勤数据 统计
  2057. /// </summary>
  2058. /// <param name="datas">数据源</param>
  2059. /// <param name="type">
  2060. /// 1-请假;2-补卡;3-出差;4-外出;100-外勤;
  2061. /// </param>
  2062. /// <param name="subTypeName">
  2063. /// 年假 事假 病假 调休假 婚嫁 产假 陪产假 丧假 补卡次数 出差 外出数 外勤 其他
  2064. /// </param>
  2065. /// <returns></returns>
  2066. private static int Fallibilitydispose(List<Sp_Item> datas, int type, string? subTypeName)
  2067. {
  2068. int num = 0;
  2069. Sp_Item _Info = datas.Where(it => it.type == type && it.name == subTypeName).FirstOrDefault();
  2070. if (_Info != null) { num = _Info.count; }
  2071. return num;
  2072. }
  2073. /// <summary>
  2074. /// 打卡数据
  2075. /// 异常数据 统计
  2076. /// </summary>
  2077. /// <returns></returns>
  2078. private static int ExceptionStatistics(List<Exception_Info> datas, int type)
  2079. {
  2080. int num = 0;
  2081. Exception_Info _Info = datas.Where(it => it.exception == type).FirstOrDefault();
  2082. if (_Info != null) { num = _Info.count; }
  2083. return num;
  2084. }
  2085. /// <summary>
  2086. /// 获取时间段内除周末 节假日外的 工作日
  2087. /// </summary>
  2088. /// <param name="startDt"></param>
  2089. /// <param name="endDt"></param>
  2090. /// <returns></returns>
  2091. public static async Task<int> GetWorkDays(string yearMonth)
  2092. {
  2093. int workdays = 0;
  2094. string sql = string.Format(@"Select * From Pm_WageIssueWorkingDay
  2095. Where Isdel = 0 And YearMonth = '{0}' ", yearMonth);
  2096. var data = await _usersRep._sqlSugar.SqlQueryable<WageYearMonthView>(sql).FirstAsync();
  2097. if (data != null)
  2098. {
  2099. workdays = data.Workdays;
  2100. }
  2101. return workdays;
  2102. }
  2103. /// <summary>
  2104. /// 获取一个类指定的属性值
  2105. /// </summary>
  2106. /// <param name="info">object对象</param>
  2107. /// <param name="field">属性名称</param>
  2108. /// <returns></returns>
  2109. public static object GetPropertyValue(object info, string field)
  2110. {
  2111. if (info == null) return null;
  2112. System.Type t = info.GetType();
  2113. IEnumerable<System.Reflection.PropertyInfo> property = from pi in t.GetProperties() where pi.Name.ToLower() == field.ToLower() select pi;
  2114. return property.First().GetValue(info, null);
  2115. }
  2116. }
  2117. }