瀏覽代碼

计算工资 SalaryCalculatorSingleAsync

leiy 1 年之前
父節點
當前提交
6d86febd1e

+ 84 - 585
OASystem/OASystem.Api/Controllers/PersonnelModuleController.cs

@@ -1,6 +1,7 @@
 using Autofac.Diagnostics;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc.RazorPages;
+using OASystem.API.OAMethodLib;
 using OASystem.API.OAMethodLib.QiYeWeChatAPI;
 using OASystem.Domain;
 using OASystem.Domain.Dtos.PersonnelModule;
@@ -103,16 +104,13 @@ namespace OASystem.API.Controllers
 
             //扣款合计 = 迟到 + 早退 + 矿工 + 未打卡 + 其他扣款 
 
-            _result = await _wageSheetRep.Get_WageSheet_ListByYearMonthAsync(yearMonth);
-            if (_result.Code != 0)
-            {
-                return Ok(JsonView(false, _result.Msg));
-            }
-            
-
             if (dto.PortType == 1)
             {
-
+                _result = await _wageSheetRep.Get_WageSheet_ListByYearMonthAsync(yearMonth);
+                if (_result.Code != 0)
+                {
+                    return Ok(JsonView(false, _result.Msg));
+                }
             }
             else if (dto.PortType == 2)
             { }
@@ -210,8 +208,6 @@ namespace OASystem.API.Controllers
             return Ok(JsonView(true, _result.Msg, _result.Data));
         }
 
-
-
         /// <summary>
         /// 计算工资
         /// </summary>
@@ -234,6 +230,11 @@ namespace OASystem.API.Controllers
 
             string thisYearMonth = dto.yearMonth;
             string preYearMonth = yearMonthDt.AddMonths(-1).ToString("yyyy-MM");
+
+            //计算本月工资起止时间
+            DateTime thisStartDt = Convert.ToDateTime(preYearMonth  + "-28");
+            DateTime thisEndDt = Convert.ToDateTime(thisYearMonth + "-27");
+
             //本月工资是否有数据 有数据则不计算
             result = await _wageSheetRep.Get_WageSheet_ListByYearMonthAsync(thisYearMonth);
             if (result.Code == 0 )
@@ -242,569 +243,31 @@ namespace OASystem.API.Controllers
             }
 
             //获取上个月工资信息
-            DateTime startDt = Convert.ToDateTime(yearMonthDt.AddMonths(-1).ToString("yyyy-MM") + "-28");
-            DateTime endDt = Convert.ToDateTime(yearMonthDt.ToString("yyyy-MM") + "-27");
-
-            string preWageSheetSql = string.Format(@"Select sys_u1.CnName Name,pm_ws.* From Pm_WageSheet pm_ws 
-                                                     Left Join Sys_Users sys_u1 On pm_ws.UserId = sys_u1.Id Where pm_ws.IsDel = 0 And YearMonth ='{0}'", preYearMonth);
-            List<WageSheetInfos> preWageSheetItems = await _wageSheetRep._sqlSugar.SqlQueryable<WageSheetInfos>(preWageSheetSql).ToListAsync();
+            List<Pm_WageSheet> preWageSheetItems = await _wageSheetRep._sqlSugar.Queryable<Pm_WageSheet>().Where(it => it.IsDel == 0 && it.YearMonth == preYearMonth).ToListAsync();
             if (preWageSheetItems.Count <= 0) 
             {
                 return Ok(JsonView(false, preYearMonth + " 工资数据不存在,请手动添加!"));
             }
-            
 
             //获取OA系统内所有用户
             var nameData = await _usersRep.GetUserNameList(1);
             List<UserNameView>? userNames = nameData.Data;
 
-            //获取所有打卡数据
-            CheckInView checkIn = await _qiYeWeChatApiService.GetCheckin_MonthDataAsync(startDt, endDt); //时间段内所有 打卡数据
-            if (checkIn.errcode != 0)
-            {
-                return Ok(JsonView(false, checkIn.errmsg));
-            }
-
-            List<Data> checkInDatas = checkIn.datas;
-
-            //获取所有打卡补卡,审批 数据
-            DateTime sp_startDt = startDt.AddDays(-10);
-            DateTime sp_centerDt = sp_startDt.AddDays(30);
-            DateTime sp_endDt = endDt.AddDays(10);
+            List<Pm_WageSheet> wageSheets = new List<Pm_WageSheet>();
 
-            List<Sp_Info> sp_Infos = new List<Sp_Info>();
-            string redisName = "ApprovalData_" + sp_startDt.Year + "_" + sp_startDt.Month;
-            string sp_InfosString = await RedisRepository.RedisFactory
-                                            .CreateRedisRepository()
-                                            .StringGetAsync<string>(redisName);//string 取
-            if (string.IsNullOrEmpty(sp_InfosString))
-            {
-                ApprovalDataView approvalData_1 = await _qiYeWeChatApiService.GetApprovalDataAsync(sp_startDt, sp_centerDt);  //时间段内所有 审批数据
-                ApprovalDataView approvalData_2 = await _qiYeWeChatApiService.GetApprovalDataAsync(sp_centerDt, sp_endDt);  //时间段内所有 审批数据
-                if (approvalData_1.errcode != 0)
-                {
-                    result.Msg = "企业微信 获取时间段内审批 Msg:" + approvalData_1.errmsg;
+            _result = await PayrollComputation.SalaryCalculatorAsync(preWageSheetItems, userNames,dto.UserId, thisYearMonth, thisStartDt, thisEndDt);
 
-                    return Ok(JsonView(false, "企业微信 获取时间段内审批 Msg:" + approvalData_1.errmsg));
-                }
-                sp_Infos.AddRange(approvalData_1.data);
-                if (approvalData_2.errcode != 0)
-                {
-                    return Ok(JsonView(false, "企业微信 获取时间段内审批 Msg:" + approvalData_2.errmsg));
-                }
-                sp_Infos.AddRange(approvalData_2.data);
+            #region 批量添加
 
-                TimeSpan ts = DateTime.Now.AddMinutes(60) - DateTime.Now; //设置redis 过期时间 60分钟
-                await RedisRepository
-                    .RedisFactory
-                    .CreateRedisRepository()
-                    .StringSetAsync<string>(redisName, JsonConvert.SerializeObject(sp_Infos), ts);//string 存
-            }
-            else
+            if (_result.Code != 0)
             {
-                sp_Infos = JsonConvert.DeserializeObject<List<Sp_Info>>(sp_InfosString);
+                return Ok(JsonView(false, _result.Msg));
             }
 
 
-            // 筛选 时间段内(请假时间,补卡时间) /审批类型(打卡补卡,请假)/审核通过的数据 
-            List<Sp_Info> sp_leave_InfosData = sp_Infos.Where(it => it.sp_status == 2 && it.spname == "请假" && it.leave.start_time_dt >= startDt && it.leave.start_time_dt <= endDt).ToList(); //请假
-            List<Sp_Info> sp_reissuecard_InfosData = sp_Infos.Where(it => it.sp_status == 2 && it.spname == "打卡补卡" && it.comm.FillingDt >= startDt && it.comm.FillingDt <= endDt).ToList();  //补卡
-
-            
-            List<Pm_WageSheet> wageSheets = new List<Pm_WageSheet>();
-            foreach (var item in preWageSheetItems)
-            {
-                Pm_WageSheet pm_wsInfo = new Pm_WageSheet();
-                pm_wsInfo = _mapper.Map<Pm_WageSheet>(item);
-
-                //补贴 金额
-                decimal meal_subsidy = 0.00M;  // 午餐(午餐10元/天)  补贴 * 计算方式:单日上午请假时长(小时)大于或者等于三小时 没有餐补
-
-                //事假 病假 总金额
-                decimal personalLeaveTotal = 0.00M,  // 事假 日薪 *计算方式:日平均工资 = 月工资/当月应出勤天数。
-                        sickLeaveTotal = 0.00M;      // 病假 日薪 *计算方式:日平均工资 = 成都市最低工资标准的80%/当月应出勤天数。 短期病假=当月15天内  
-
-                //扣款金额
-                decimal beLate_deduction = 0.00M,         // 迟到 扣款金额 *计算方式:
-                                                          // 一个自然月内,不足 10 分钟的迟到/早退,不超过 2 次的部分,不做处罚;3 次及以上,按50元 / 次处罚;
-                                                          // 超过 10 分钟(含 10 分钟),不足 60 分钟的迟到/早退,按 50 元/次处罚;
-                                                          // 超过 60 分钟(含 60 分钟),不足 3 小时的迟到/早退,且无请假者,按旷工半日处理;超过3 小时的迟到 / 早退,且无请假者,按旷工一日处理。
-
-                        early_deduction = 0.00M,          // 早退 扣款金额
-                        absenteeism_deduction = 0.00M,    // 旷工 扣款金额 *计算方式:旷工扣发当日工资
-                        unprinted_deduction = 0.00M,      // 未打卡 扣款金额 *计算方式:
-                                                          // 试用期员工每月有 2 次 补卡机会,超过 2 次不足 5 次的部分,按 10 元 / 次处罚,5 次及以上的漏卡,按 50 元 / 次处罚;
-                                                          // 正式员工每月 3 次以内的补卡,按 10 元 / 次处罚,3 次及以上的漏卡,按 50 元 / 次处罚。
-                        sickLeave_deduction = 0.00M,
-                        other_deduction = 0.00M;          // 其他 扣款金额
-
-                decimal meal_deduction = 0.00M;           // 餐补 扣款金额
-                decimal reissuecard_deduction = 0.00M;    // 补卡 扣款金额
-
-                //打卡数据
-                Data? checkInData = checkInDatas.Where(it => it.base_info.name == item.Name).FirstOrDefault();
-                if (checkInData == null) { continue; }
-                string acctid = checkInData.base_info.acctid; //用户Id
-               
-                //当月总计数据
-                Summary_Info? summary_Info = checkInData.summary_info;
-                if (summary_Info == null ) { continue; }
-
-                int work_days = summary_Info.work_days;   //应出勤天数
-                int regular_days = summary_Info.regular_days;  //正常出勤天数
-
-                meal_subsidy = work_days * 10; //应发放餐补
-
-                #region 计算日工资 正常日薪 事假日薪 病假日薪
-
-                //月 - 应发工资
-                decimal amountPayable = pm_wsInfo.Basic + pm_wsInfo.Floats + pm_wsInfo.PostAllowance + pm_wsInfo.GarmentWashSubsidies + pm_wsInfo.CommunicationSubsidies +
-                    pm_wsInfo.TrafficSubsidies + pm_wsInfo.InformationSecurityFee + pm_wsInfo.OperationBonus + pm_wsInfo.SpecialAllowance + pm_wsInfo.OtherSubsidies + pm_wsInfo.GroupCost;
-
-                // 日薪 = 事假日薪 *计算方式:日平均工资 = 月工资/当月应出勤天数。
-                decimal dailyWage = amountPayable / work_days;
-
-                // 病假日薪 *计算方式:日平均工资 = 成都市最低工资标准的80%/当月应出勤天数。 短期病假=当月15天内 
-                decimal sickLeave_dailywage = _chengDuMinimumWage / work_days;
-
-                //病假 一天扣款  
-                sickLeave_deduction = dailyWage - sickLeave_dailywage;
-
-                #endregion
-
-                int annualLeaveNum = 0,    //年假
-                    personalLeaveNum = 0,  //事假
-                    sickLeaveNum = 0,      //病假
-                    lieuLeaveNum = 0,      //调休假
-                    marriageLeaveNum = 0,  //婚嫁
-                    maternityLeaveNum = 0, //产假
-                    paternityLeaveNum = 0, //陪产假
-                    funeralLeaveNum = 0,   //丧假
-                    reissueCardNum = 0,    //补卡 次数
-                    evectionNum = 0,       //出差 次数
-                    outIngNum = 0,         //外出 次数
-                    outWorkNum = 0,        //外勤 次数
-                    otherLeaveNum = 0;     //其他
-
-
-                #region 假勤 处理  1-请假;2-补卡;3-出差;4-外出;100-外勤;
-
-                List<Sp_Item>? sp_items = checkInData.sp_items.Where(it => it.count != 0).ToList();
-                if (sp_items != null && sp_items.Count > 0)
-                {
-                    annualLeaveNum = Fallibilitydispose(sp_items, 1, "年假");
-                    personalLeaveNum = Fallibilitydispose(sp_items, 1, "事假");
-                    sickLeaveNum = Fallibilitydispose(sp_items, 1, "病假");
-                    lieuLeaveNum = Fallibilitydispose(sp_items, 1, "调休假");
-                    marriageLeaveNum = Fallibilitydispose(sp_items, 1, "婚嫁");
-                    maternityLeaveNum = Fallibilitydispose(sp_items, 1, "产假");
-                    paternityLeaveNum = Fallibilitydispose(sp_items, 1, "陪产假");
-                    funeralLeaveNum = Fallibilitydispose(sp_items, 1, "丧假");
-                    otherLeaveNum = Fallibilitydispose(sp_items, 1, "其他");
-                    reissueCardNum = Fallibilitydispose(sp_items, 2, "补卡次数");
-                    evectionNum = Fallibilitydispose(sp_items, 3, "出差");
-                    outIngNum = Fallibilitydispose(sp_items, 4, "外出");
-                    outWorkNum = Fallibilitydispose(sp_items, 3, "外勤");
-                }
-
-                #region 请假类型金额/餐补 处理
-
-                List<Sp_Info> sp_leave_item_infosData = sp_leave_InfosData.Where(it => it.spname == "请假" && it.apply_name == item.Name).ToList();
-
-                List<Ex_Items> ex_Items = new List<Ex_Items>();//假勤 And 打卡备注集合
-                Ex_Items ex_Items_jq = new Ex_Items() { Type = "假勤" };   //假勤
-                List<Ex_Item> ex_ItemInfos = new List<Ex_Item>();
-
-                foreach (Sp_Info sp_item in sp_leave_item_infosData)
-                {
-                    Leave? sp_leave = sp_item.leave;
-                    if (sp_leave != null)
-                    {
-
-                        //请假时长
-                        double leaveLength = (sp_leave.end_time_dt - sp_leave.start_time_dt).TotalHours;
-
-                        string typeName = string.Empty;
-                        //leave_type 1年假;2事假;3病假;4调休假;5婚假;6产假;7陪产假;8其他
-                        switch (sp_leave.leave_type)
-                        {
-                            case 1:    //年假
-                                typeName = "年假";
-                                if (sp_leave.timeunit == 0) //半天
-                                {
-                                    meal_deduction += 10;
-                                }
-                                else if (sp_leave.timeunit == 1) //小时
-                                {
-                                    if (sp_leave.duration >= 3 && sp_leave.duration <= 7.5) //7.5小时 一天
-                                    {
-                                        meal_deduction += 10;
-                                    }
-                                    else if (sp_leave.duration > 7.5)
-                                    {
-                                        decimal daysPrice = Convert.ToDecimal(sp_leave.duration / 7.5 * 10);
-                                        meal_deduction += daysPrice;
-                                    }
-                                }
-                                break;
-                            case 2:    //事假 需调整
-                                typeName = "事假";
-                                if (sp_leave.timeunit == 0) //半天
-                                {
-                                    meal_deduction += 10;
-                                    personalLeaveTotal += dailyWage / 2;
-                                }
-                                else if (sp_leave.timeunit == 1) //小时
-                                {
-                                    if (sp_leave.duration >= 3 && sp_leave.duration <= 7.5) //7.5小时 一天
-                                    {
-                                        meal_deduction += 10;
-                                    }
-                                    else if (sp_leave.duration > 7.5)
-                                    {
-                                        decimal daysPrice = Convert.ToDecimal(sp_leave.duration / 7.5 * 10);
-                                        meal_deduction += daysPrice;
-                                    }
-                                }
-                                break;
-                            case 3:    //病假 需调整
-                                typeName = "病假";
-                                if (sp_leave.timeunit == 0) //半天
-                                {
-                                    meal_deduction += 10;
-                                    sickLeaveTotal += sickLeave_deduction / 2;
-                                }
-                                else if (sp_leave.timeunit == 1) //小时
-                                {
-                                    if (sp_leave.duration >= 3 && sp_leave.duration <= 7.5) //7.5小时 一天
-                                    {
-                                        meal_deduction += 10;
-                                    }
-                                    else if (sp_leave.duration > 7.5)
-                                    {
-                                        decimal daysPrice = Convert.ToDecimal(sp_leave.duration / 7.5 * 10);
-                                        meal_deduction += daysPrice;
-                                    }
-                                }
-                                break;
-                            case 4:    //调休假
-                                typeName = "调休假";
-                                if (sp_leave.timeunit == 0) //半天
-                                {
-                                    meal_deduction += 10;
-                                }
-                                else if (sp_leave.timeunit == 1) //小时
-                                {
-                                    if (sp_leave.duration >= 3 && sp_leave.duration <= 7.5) //7.5小时 一天
-                                    {
-                                        meal_deduction += 10;
-                                    } 
-                                    else if (sp_leave.duration > 7.5)
-                                    {
-                                        decimal daysPrice = Convert.ToDecimal(sp_leave.duration / 7.5 * 10);
-                                        meal_deduction += daysPrice;
-                                    }
-                                }
-                                break;
-                            case 5:    //婚假
-                                typeName = "婚假";
-                                if (sp_leave.timeunit == 0) //半天
-                                {
-                                    meal_deduction += 10;
-                                }
-                                else if (sp_leave.timeunit == 1) //小时
-                                {
-                                    if (sp_leave.duration >= 3 && sp_leave.duration <= 7.5) //7.5小时 一天
-                                    {
-                                        meal_deduction += 10;
-                                    }
-                                    else if (sp_leave.duration > 7.5)
-                                    {
-                                        decimal daysPrice = Convert.ToDecimal(sp_leave.duration / 7.5 * 10);
-                                        meal_deduction += daysPrice;
-                                    }
-                                }
-                                break;
-                            case 6:    //产假
-                                typeName = "产假";
-                                if (sp_leave.timeunit == 0) //半天
-                                {
-                                    meal_deduction += 10;
-                                }
-                                else if (sp_leave.timeunit == 1) //小时
-                                {
-                                    if (sp_leave.duration >= 3 && sp_leave.duration <= 7.5) //7.5小时 一天
-                                    {
-                                        meal_deduction += 10;
-                                    }
-                                    else if (sp_leave.duration > 7.5)
-                                    {
-                                        decimal daysPrice = Convert.ToDecimal(sp_leave.duration / 7.5 * 10);
-                                        meal_deduction += daysPrice;
-                                    }
-                                }
-                                break;
-                            case 7:    //陪产假
-                                typeName = "陪产假";
-                                if (sp_leave.timeunit == 0) //半天
-                                {
-                                    meal_deduction += 10;
-                                }
-                                else if (sp_leave.timeunit == 1) //小时
-                                {
-                                    if (sp_leave.duration >= 3 && sp_leave.duration <= 7.5) //7.5小时 一天
-                                    {
-                                        meal_deduction += 10;
-                                    }
-                                    else if (sp_leave.duration > 7.5)
-                                    {
-                                        decimal daysPrice = Convert.ToDecimal(sp_leave.duration / 7.5 * 10);
-                                        meal_deduction += daysPrice;
-                                    }
-                                }
-                                break;
-                            default:
-                                break;
-                        }
-
-                        Ex_Item ex_Item = new Ex_Item() {
-                            SubTypeId = sp_leave.leave_type,
-                            SubType = typeName,
-                            Start_time_dt = sp_leave.start_time_dt,
-                            End_time_dt = sp_leave.end_time_dt,
-                            Duration = sp_leave.duration,
-                            Reason = sp_leave.reason,
-                            Apply_time_dt = sp_item.apply_time_dt,
-                            Approval_name = sp_item.approval_name,
-                        };
-                        ex_ItemInfos.Add(ex_Item);
-                    }
-                }
-
-                if (ex_ItemInfos.Count > 0)
-                {
-                    ex_Items_jq.Ex_ItemInfo = ex_ItemInfos.OrderBy(it => it.SubTypeId).ThenBy(it => it.Start_time_dt).ToList();
-                    ex_Items.Add(ex_Items_jq);
-                }
-
-                #endregion
-
-                #endregion
-
-
-                #region 打卡补卡 处理
-
-                if (reissueCardNum == 3)
-                {
-                    reissuecard_deduction += 10;
-                }
-                else if (reissueCardNum >= 4)
-                {
-                    reissuecard_deduction += 50;
-                }
-
-                #endregion
-
-                Ex_Items ex_Items_dk = new Ex_Items() { Type = "打卡" };    //打卡
-                //List<Ex_Item> ex_reissuecard_Items = new List<Ex_Item>();
-                List<dynamic> ex_reissuecard_Items = new List<dynamic>();
-                List<Sp_Info> sp_reissuecard_item_InfosData = sp_reissuecard_InfosData.Where(it => it.apply_name == item.Name).ToList();
-
-                #region 打卡异常处理 统计 1-迟到;2-早退;3-缺卡;4-旷工;5-地点异常;6-设备异常;
-
-                int beLateNum = 0,           // 1-迟到;
-                    leaveEarlyNum = 0,       // 2-早退;
-                    dummyDeckNum = 0,        // 3-缺卡;
-                    minerNum = 0,            // 4-旷工;
-                    locationAnomalyNum = 0,  // 5-地点异常;
-                    unitExNum = 0;           // 6-设备异常;
-
-                if (summary_Info.except_days > 0)
-                {
-                    List<Exception_Info>? ex_infos = checkInData.exception_infos;
-                    if (ex_infos != null && ex_infos.Count >= 0)
-                    {
-                        beLateNum = ExceptionStatistics(ex_infos, 1);
-                        leaveEarlyNum = ExceptionStatistics(ex_infos, 2);
-                        dummyDeckNum = ExceptionStatistics(ex_infos, 3);
-                        minerNum = ExceptionStatistics(ex_infos, 4);
-                        locationAnomalyNum = ExceptionStatistics(ex_infos, 5);
-                        unitExNum = ExceptionStatistics(ex_infos, 6);
-                    }
-                }
-
-                foreach (Sp_Info sp_reissuecard_item in sp_reissuecard_item_InfosData)
-                {
-                    DateTime apply_time_dt = sp_reissuecard_item.apply_time_dt; //申请时间
-                    List<string>? approval_name = sp_reissuecard_item.approval_name; //审核人
-
-                    Comm sp_comm = sp_reissuecard_item.comm;
-                    if (sp_comm != null)
-                    {
-                        if (sp_comm.applydata != null )
-                        {
-                            List<ApplyInfo>  applyInfos = sp_comm.applydata;
-                            if (applyInfos.Count > 0)
-                            {
-                                //Ex_Item ex_reissuecard_Item = new Ex_Item();
-                                dynamic ex_reissuecard_Item = null;
-                                string text = applyInfos.Where(it => it.type == "text").FirstOrDefault().value.ToString(); //异常状态
-                                DateTime? datehour = applyInfos.Where(it => it.type == "datehour").FirstOrDefault().valueDt;//补卡时间
-                                string textarea = applyInfos.Where(it => it.type == "textarea").FirstOrDefault().value.ToString();//补卡事由
-                                if (text.Contains("未打卡"))
-                                {
-                                    ex_reissuecard_Item = new
-                                    {
-                                        SubTypeId = 0,
-                                        SubType = "未打卡",
-                                        title = text,
-                                        datehour = datehour == null ? "" : Convert.ToDateTime(datehour).ToString("yyyy-MM-dd HH:mm:ss"),
-                                        textarea = textarea,
-                                        apply_time_dt = apply_time_dt,
-                                        approval_name = approval_name
-                                    };
-                                }
-                                else if (text.Contains("迟到"))
-                                {
-                                    ex_reissuecard_Item = new
-                                    {
-                                        SubTypeId = 1,
-                                        SubType = "迟到",
-                                        title = text,
-                                        datehour = datehour == null? "": Convert.ToDateTime(datehour).ToString("yyyy-MM-dd HH:mm:ss"),
-                                        textarea = textarea,
-                                        apply_time_dt = apply_time_dt,
-                                        approval_name = approval_name
-                                    };
-                                }
-                                else if (text.Contains("早退"))
-                                {
-                                    ex_reissuecard_Item = new
-                                    {
-                                        SubTypeId = 2,
-                                        SubType = "早退",
-                                        title = text,
-                                        datehour = datehour == null ? "" : Convert.ToDateTime(datehour).ToString("yyyy-MM-dd HH:mm:ss"),
-                                        textarea = textarea,
-                                        apply_time_dt = apply_time_dt,
-                                        approval_name = approval_name
-                                    };
-                                }
-                                else if (text.Contains("缺卡"))
-                                {
-                                    ex_reissuecard_Item = new
-                                    {
-                                        SubTypeId = 3,
-                                        SubType = "缺卡",
-                                        title = text,
-                                        datehour = datehour == null ? "" : Convert.ToDateTime(datehour).ToString("yyyy-MM-dd HH:mm:ss"),
-                                        textarea = textarea,
-                                        apply_time_dt = apply_time_dt,
-                                        approval_name = approval_name
-                                    };
-                                }
-                                else if (text.Contains("旷工"))
-                                {
-                                    ex_reissuecard_Item = new
-                                    {
-                                        SubTypeId = 4,
-                                        SubType = "旷工",
-                                        title = text,
-                                        datehour = datehour == null ? "" : Convert.ToDateTime(datehour).ToString("yyyy-MM-dd HH:mm:ss"),
-                                        textarea = textarea,
-                                        apply_time_dt = apply_time_dt,
-                                        approval_name = approval_name
-                                    };
-                                }
-                                else if (text.Contains("地点异常"))
-                                {
-                                    ex_reissuecard_Item = new
-                                    {
-                                        SubTypeId = 5,
-                                        SubType = "地点异常",
-                                        title = text,
-                                        datehour = datehour == null ? "" : Convert.ToDateTime(datehour).ToString("yyyy-MM-dd HH:mm:ss"),
-                                        textarea = textarea,
-                                        apply_time_dt = apply_time_dt,
-                                        approval_name = approval_name
-                                    };
-                                }
-                                else if (text.Contains("设备异常"))
-                                {
-                                    ex_reissuecard_Item = new
-                                    {
-                                        SubTypeId = 6,
-                                        SubType = "设备异常",
-                                        title = text,
-                                        datehour = datehour == null ? "" : Convert.ToDateTime(datehour).ToString("yyyy-MM-dd HH:mm:ss"),
-                                        textarea = textarea,
-                                        apply_time_dt = apply_time_dt,
-                                        approval_name = approval_name
-                                    };
-                                }
-                                if (ex_reissuecard_Item != null)
-                                {
-                                    ex_reissuecard_Items.Add(ex_reissuecard_Item);
-                                }
-                            }
-                        }
-                    }
-                }
-
-                if (ex_reissuecard_Items.Count>0)
-                {
-                    ex_Items_dk.Ex_ItemInfo = ex_reissuecard_Items.OrderBy(it => it.SubTypeId).ThenBy(it => it.datehour).ToList();
-                    ex_Items.Add(ex_Items_dk);
-                }
-
-                #endregion
-
-
-                #region 应发合计 实发合计 扣款合计(假勤扣款,其他扣款,社保扣款,公积金代扣,个税扣款)
-
-                decimal mealTotal = meal_subsidy - meal_deduction;  //餐补
-                decimal salaryTotal = amountPayable + mealTotal;    //应发合计
-
-                //扣款合计 不含个税
-                decimal eductionTotal = sickLeaveTotal + personalLeaveTotal + beLate_deduction + early_deduction + absenteeism_deduction + unprinted_deduction + other_deduction +
-                    pm_wsInfo.WithholdingInsurance + pm_wsInfo.ReservedFunds;
-                decimal actualReleaseTotal = salaryTotal - eductionTotal; //实发合计 * 不含个税
-
-
-                #endregion
-
-                #region 处理当月工资数据
-                pm_wsInfo.YearMonth = thisYearMonth;
-                pm_wsInfo.StartDate = startDt.ToString("yyyy-MM-dd");
-                pm_wsInfo.EndDate = endDt.ToString("yyyy-MM-dd");
-
-                pm_wsInfo.SickLeave = sickLeaveTotal;           //病假
-                pm_wsInfo.SomethingFalse = personalLeaveTotal;  //事假
-                pm_wsInfo.LateTo = beLate_deduction;            //迟到
-                pm_wsInfo.LeaveEarly = early_deduction;         //早退
-                pm_wsInfo.Absenteeism = absenteeism_deduction;  //旷工
-                pm_wsInfo.NotPunch = unprinted_deduction;       //未打卡
-                pm_wsInfo.OtherDeductions = other_deduction;    //其他
-                pm_wsInfo.Ex_ItemsRemark = JsonConvert.SerializeObject(ex_Items);  //
-                pm_wsInfo.Mealsupplement = mealTotal;          //餐补
 
-                pm_wsInfo.Should = salaryTotal;            //应发合计
-                pm_wsInfo.TotalDeductions = eductionTotal; //扣款合计
-                pm_wsInfo.TotalRealHair = actualReleaseTotal; //实发合计
-                pm_wsInfo.AfterTax = actualReleaseTotal - pm_wsInfo.WithholdingTax; //税后工资
+            wageSheets = _result.Data;
 
-                pm_wsInfo.LastUpdateUserId = dto.UserId;
-                pm_wsInfo.LastUpdateDt = DateTime.Now;
-                pm_wsInfo.CreateUserId = dto.UserId;
-                pm_wsInfo.CreateTime = DateTime.Now;
-
-                #endregion
-
-
-                wageSheets.Add(pm_wsInfo);
-            }
-
-            #region 批量添加
             var add = await _wageSheetRep._sqlSugar.Insertable(wageSheets).ExecuteCommandAsync();
             if (add <= 0)
             {
@@ -831,49 +294,85 @@ namespace OASystem.API.Controllers
                     ).ToList();
             #endregion
 
-
-
-
             return Ok(JsonView(true,"操作成功!", wageSheetItems));
         }
 
+
         /// <summary>
-        /// 打卡数据
-        /// 假勤数据 统计
+        /// 计算工资 By YearMonth And UserId
         /// </summary>
-        /// <param name="datas">数据源</param>
-        /// <param name="type">
-        /// 1-请假;2-补卡;3-出差;4-外出;100-外勤;
-        /// </param>
-        /// <param name="subTypeName">
-        /// 年假 事假 病假 调休假 婚嫁 产假  陪产假 丧假 补卡次数 出差 外出数 外勤 其他
-        /// </param>
         /// <returns></returns>
-        private int Fallibilitydispose(List<Sp_Item> datas, int type,string? subTypeName)
+        [HttpPost]
+        [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
+        public async Task<IActionResult> SalaryCalculatorSingleAsync(SalaryCalculatorSingleDto dto)
         {
-            int num = 0;
+            Result result = new Result();
 
-            Sp_Item _Info = datas.Where(it => it.type == type && it.name == subTypeName).FirstOrDefault();
-            if (_Info != null) { num = _Info.count; }
+            //参数处理
+            string ymFormat = "yyyy-MM";
+            string ymdFormat = "yyyy-MM-dd";
+            DateTime yearMonthDt,startDt,endDt;
+            bool yearMonthDtIsValid = DateTime.TryParseExact(dto.YearMonth, ymFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out yearMonthDt);
+            bool startDtIsValid = DateTime.TryParseExact(dto.StartDate, ymdFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out startDt);
+            bool endDtIsValid = DateTime.TryParseExact(dto.EndDate, ymdFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out endDt);
 
-            return num;
-        }
+            if (!yearMonthDtIsValid)
+                return Ok(JsonView(false, "年月格式错误!正确时间格式:yyyy-MM  "));
 
-        /// <summary>
-        /// 打卡数据
-        /// 异常数据 统计
-        /// </summary>
-        /// <returns></returns>
-        private int ExceptionStatistics(List<Exception_Info> datas,int type)
-        {
-            int num = 0;
+            if (!startDtIsValid)
+                return Ok(JsonView(false, "开始时间格式错误!正确时间格式:yyyy-MM-dd  "));
 
-            Exception_Info _Info = datas.Where(it => it.exception == type).FirstOrDefault();
-            if (_Info != null) { num = _Info.count; }
+            if (!yearMonthDtIsValid)
+                return Ok(JsonView(false, "结束时间格式错误!正确时间格式:yyyy-MM-dd  "));
 
-            return num;
-        }
+            //本月工资是否有数据 有数据则不计算
+            result = await _wageSheetRep.Get_WageSheet_ListByYearMonthAsync(dto.YearMonth);
+            if (result.Code == 0)
+            {
+                return Ok(JsonView(false, dto.YearMonth + " 工资数据已存在,若无人员工资请手动添加!"));
+            }
+
+
+            List<Pm_WageSheet> wageSheets = new List<Pm_WageSheet>();
+            Pm_WageSheet wageSheet = _mapper.Map<Pm_WageSheet>(dto);
+            wageSheets.Add(wageSheet);
+            //获取OA系统内所有用户
+            var nameData = await _usersRep.GetUserNameList(1);
+            List<UserNameView>? userNames = nameData.Data;
+
+            _result = await PayrollComputation.SalaryCalculatorAsync(wageSheets, userNames, dto.UserId, dto.YearMonth, startDt, endDt);
 
+            if (_result.Code != 0)
+            {
+                return Ok(JsonView(false, _result.Msg));
+            }
+
+            List<Pm_WageSheet> wageSheets1 = new List<Pm_WageSheet>();
+            wageSheets1 = _result.Data;
+            #region 处理返回数据
+
+
+            List<WageSheetInfoView> wageSheetItems = new List<WageSheetInfoView>();
+            wageSheetItems = _mapper.Map<List<WageSheetInfoView>>(wageSheets1);
+            wageSheetItems = wageSheetItems.Select(it =>
+                {
+                    UserNameView? uName1 = new UserNameView();
+                    UserNameView? uName2 = new UserNameView();
+                    uName1 = userNames.Where(it1 => it.UserId == it1.Id).FirstOrDefault();
+                    if (uName1 != null) it.Name = uName1.CnName;
+
+                    uName2 = userNames.Where(it1 => it.LastUpdateUserId == it1.Id).FirstOrDefault();
+                    if (uName2 != null) it.LastUpdateUserName = uName2.CnName;
+
+                    return it;
+                }
+            ).ToList();
+            #endregion
+
+           
+
+            return Ok(JsonView(true, "操作成功!", wageSheetItems[0]));
+        }
         #endregion
 
     }

+ 4 - 3
OASystem/OASystem.Api/OAMethodLib/GeneralMethod.cs

@@ -1,4 +1,6 @@
-using OASystem.Domain.Entities.System;
+using OASystem.Domain.Entities.PersonnelModule;
+using OASystem.Domain.Entities.System;
+using OASystem.Domain.ViewModels.PersonnelModule;
 using System.IdentityModel.Tokens.Jwt;
 using System.Security.Claims;
 
@@ -7,8 +9,6 @@ namespace OASystem.API.OAMethodLib
     public static class GeneralMethod
     {
 
-        
-
         #region 消息
 
 
@@ -126,5 +126,6 @@ namespace OASystem.API.OAMethodLib
 
         #endregion
 
+
     }
 }

+ 603 - 0
OASystem/OASystem.Api/OAMethodLib/PayrollComputation.cs

@@ -0,0 +1,603 @@
+using OASystem.API.OAMethodLib.QiYeWeChatAPI;
+using OASystem.Domain;
+using OASystem.Domain.Entities.PersonnelModule;
+using OASystem.Domain.ViewModels.PersonnelModule;
+using OASystem.Domain.ViewModels.QiYeWeChat;
+using OASystem.Infrastructure.Repositories.Groups;
+
+namespace OASystem.API.OAMethodLib
+{
+    /// <summary>
+    /// 工资计算
+    /// </summary>
+    public static class PayrollComputation
+    {
+        private static Result _result = new Result();
+        private static readonly IQiYeWeChatApiService _qiYeWeChatApiService = AutofacIocManager.Instance.GetService<IQiYeWeChatApiService>(); 
+        private static readonly UsersRepository _usersRep = AutofacIocManager.Instance.GetService<UsersRepository>();
+        private static readonly IMapper _mapper = AutofacIocManager.Instance.GetService<IMapper>();
+        private static readonly decimal _chengDuMinimumWage = 2100.00M;
+
+        /// <summary>
+        /// 计算工资
+        /// </summary>
+        /// <param name="pm_WageSheetDattaSources"></param>
+        /// <param name="userNames"></param>
+        /// <param name="thisYearMonth"></param>
+        /// <param name="startDt"></param>
+        /// <param name="endDt"></param>
+        /// <returns></returns>
+        public static async Task<Result> SalaryCalculatorAsync(
+            List<Pm_WageSheet> pm_WageSheetDattaSources, List<UserNameView> userNames,int userId, string thisYearMonth, DateTime startDt, DateTime endDt)
+        {
+            if (pm_WageSheetDattaSources.Count <= 0)
+            {
+                _result.Msg = "计算工资传入数据为空!";
+                return _result;
+            }
+
+            if (userNames.Count <= 0 )
+            {
+                var nameData = await _usersRep.GetUserNameList(1);
+                userNames = nameData.Data;
+            }
+
+
+            //获取所有打卡数据
+            CheckInView checkIn = await _qiYeWeChatApiService.GetCheckin_MonthDataAsync(startDt, endDt); //时间段内所有 打卡数据
+            if (checkIn.errcode != 0)
+            {
+                _result.Msg = checkIn.errmsg;
+                return _result;
+            }
+
+            List<Data> checkInDatas = checkIn.datas;
+
+            List<Sp_Info> sp_Infos = new List<Sp_Info>();
+            sp_Infos = await _qiYeWeChatApiService.GetApprovalDataRedisAsync(startDt, endDt); //时间段内所有 审批数据
+
+            if (sp_Infos.Count <= 0)
+            {
+                string errMsg = startDt + " - " + endDt + "审批数据获取失败!";
+                return _result;
+            }
+
+            // 筛选 时间段内(请假时间,补卡时间) /审批类型(打卡补卡,请假)/审核通过的数据 
+            List<Sp_Info> sp_leave_InfosData = sp_Infos.Where(it => it.sp_status == 2 && it.spname == "请假" && it.leave.start_time_dt >= startDt && it.leave.start_time_dt <= endDt).ToList(); //请假
+            List<Sp_Info> sp_reissuecard_InfosData = sp_Infos.Where(it => it.sp_status == 2 && it.spname == "打卡补卡" && it.comm.FillingDt >= startDt && it.comm.FillingDt <= endDt).ToList();  //补卡
+
+            foreach (var pm_wsInfo in pm_WageSheetDattaSources)
+            {
+                string itemName = userNames.Where(it => it.Id == pm_wsInfo.UserId).FirstOrDefault().CnName;
+                //补贴 金额
+                decimal meal_subsidy = 0.00M;  // 午餐(午餐10元/天)  补贴 * 计算方式:单日上午请假时长(小时)大于或者等于三小时 没有餐补
+
+                //事假 病假 总金额
+                decimal personalLeaveTotal = 0.00M,  // 事假 日薪 *计算方式:日平均工资 = 月工资/当月应出勤天数。
+                        sickLeaveTotal = 0.00M;      // 病假 日薪 *计算方式:日平均工资 = 成都市最低工资标准的80%/当月应出勤天数。 短期病假=当月15天内  
+
+                //扣款金额
+                decimal beLate_deduction = 0.00M,         // 迟到 扣款金额 *计算方式:
+                                                          // 一个自然月内,不足 10 分钟的迟到/早退,不超过 2 次的部分,不做处罚;3 次及以上,按50元 / 次处罚;
+                                                          // 超过 10 分钟(含 10 分钟),不足 60 分钟的迟到/早退,按 50 元/次处罚;
+                                                          // 超过 60 分钟(含 60 分钟),不足 3 小时的迟到/早退,且无请假者,按旷工半日处理;超过3 小时的迟到 / 早退,且无请假者,按旷工一日处理。
+
+                        early_deduction = 0.00M,          // 早退 扣款金额
+                        absenteeism_deduction = 0.00M,    // 旷工 扣款金额 *计算方式:旷工扣发当日工资
+                        unprinted_deduction = 0.00M,      // 未打卡 扣款金额 *计算方式:
+                                                          // 试用期员工每月有 2 次 补卡机会,超过 2 次不足 5 次的部分,按 10 元 / 次处罚,5 次及以上的漏卡,按 50 元 / 次处罚;
+                                                          // 正式员工每月 3 次以内的补卡,按 10 元 / 次处罚,3 次及以上的漏卡,按 50 元 / 次处罚。
+                        sickLeave_deduction = 0.00M,
+                        other_deduction = 0.00M;          // 其他 扣款金额
+
+                decimal meal_deduction = 0.00M;           // 餐补 扣款金额
+                decimal reissuecard_deduction = 0.00M;    // 补卡 扣款金额
+
+                //打卡数据
+                Data? checkInData = checkInDatas.Where(it => it.base_info.name == itemName).FirstOrDefault();
+                if (checkInData == null) { continue; }
+                string acctid = checkInData.base_info.acctid; //用户Id
+
+                //当月总计数据
+                Summary_Info? summary_Info = checkInData.summary_info;
+                if (summary_Info == null) { continue; }
+
+                int work_days = summary_Info.work_days;   //应出勤天数
+                int regular_days = summary_Info.regular_days;  //正常出勤天数
+
+                meal_subsidy = work_days * 10; //应发放餐补
+
+                #region 计算日工资 正常日薪 事假日薪 病假日薪
+
+                //月 - 应发工资
+                decimal amountPayable = pm_wsInfo.Basic + pm_wsInfo.Floats + pm_wsInfo.PostAllowance + pm_wsInfo.GarmentWashSubsidies + pm_wsInfo.CommunicationSubsidies +
+                    pm_wsInfo.TrafficSubsidies + pm_wsInfo.InformationSecurityFee + pm_wsInfo.OperationBonus + pm_wsInfo.SpecialAllowance + pm_wsInfo.OtherSubsidies + pm_wsInfo.GroupCost;
+
+                // 日薪 = 事假日薪 *计算方式:日平均工资 = 月工资/当月应出勤天数。
+                decimal dailyWage = amountPayable / work_days;
+
+                // 病假日薪 *计算方式:日平均工资 = 成都市最低工资标准的80%/当月应出勤天数。 短期病假=当月15天内 
+                decimal sickLeave_dailywage = _chengDuMinimumWage / work_days;
+
+                //病假 一天扣款  
+                sickLeave_deduction = dailyWage - sickLeave_dailywage;
+
+                #endregion
+
+                int annualLeaveNum = 0,    //年假
+                    personalLeaveNum = 0,  //事假
+                    sickLeaveNum = 0,      //病假
+                    lieuLeaveNum = 0,      //调休假
+                    marriageLeaveNum = 0,  //婚嫁
+                    maternityLeaveNum = 0, //产假
+                    paternityLeaveNum = 0, //陪产假
+                    funeralLeaveNum = 0,   //丧假
+                    reissueCardNum = 0,    //补卡 次数
+                    evectionNum = 0,       //出差 次数
+                    outIngNum = 0,         //外出 次数
+                    outWorkNum = 0,        //外勤 次数
+                    otherLeaveNum = 0;     //其他
+
+
+                #region 假勤 处理  1-请假;2-补卡;3-出差;4-外出;100-外勤;
+
+                List<Sp_Item>? sp_items = checkInData.sp_items.Where(it => it.count != 0).ToList();
+                if (sp_items != null && sp_items.Count > 0)
+                {
+                    annualLeaveNum = Fallibilitydispose(sp_items, 1, "年假");
+                    personalLeaveNum = Fallibilitydispose(sp_items, 1, "事假");
+                    sickLeaveNum = Fallibilitydispose(sp_items, 1, "病假");
+                    lieuLeaveNum = Fallibilitydispose(sp_items, 1, "调休假");
+                    marriageLeaveNum = Fallibilitydispose(sp_items, 1, "婚嫁");
+                    maternityLeaveNum = Fallibilitydispose(sp_items, 1, "产假");
+                    paternityLeaveNum = Fallibilitydispose(sp_items, 1, "陪产假");
+                    funeralLeaveNum = Fallibilitydispose(sp_items, 1, "丧假");
+                    otherLeaveNum = Fallibilitydispose(sp_items, 1, "其他");
+                    reissueCardNum = Fallibilitydispose(sp_items, 2, "补卡次数");
+                    evectionNum = Fallibilitydispose(sp_items, 3, "出差");
+                    outIngNum = Fallibilitydispose(sp_items, 4, "外出");
+                    outWorkNum = Fallibilitydispose(sp_items, 3, "外勤");
+                }
+
+                #region 请假类型金额/餐补 处理
+
+                List<Sp_Info> sp_leave_item_infosData = sp_leave_InfosData.Where(it => it.spname == "请假" && it.apply_name == itemName).ToList();
+
+                List<Ex_Items> ex_Items = new List<Ex_Items>();//假勤 And 打卡备注集合
+                Ex_Items ex_Items_jq = new Ex_Items() { Type = "假勤" };   //假勤
+                List<Ex_Item> ex_ItemInfos = new List<Ex_Item>();
+
+                foreach (Sp_Info sp_item in sp_leave_item_infosData)
+                {
+                    Leave? sp_leave = sp_item.leave;
+                    if (sp_leave != null)
+                    {
+
+                        //请假时长
+                        double leaveLength = (sp_leave.end_time_dt - sp_leave.start_time_dt).TotalHours;
+
+                        string typeName = string.Empty;
+                        //leave_type 1年假;2事假;3病假;4调休假;5婚假;6产假;7陪产假;8其他
+                        switch (sp_leave.leave_type)
+                        {
+                            case 1:    //年假
+                                typeName = "年假";
+                                if (sp_leave.timeunit == 0) //半天
+                                {
+                                    meal_deduction += 10;
+                                }
+                                else if (sp_leave.timeunit == 1) //小时
+                                {
+                                    if (sp_leave.duration >= 3 && sp_leave.duration <= 7.5) //7.5小时 一天
+                                    {
+                                        meal_deduction += 10;
+                                    }
+                                    else if (sp_leave.duration > 7.5)
+                                    {
+                                        decimal daysPrice = Convert.ToDecimal(sp_leave.duration / 7.5 * 10);
+                                        meal_deduction += daysPrice;
+                                    }
+                                }
+                                break;
+                            case 2:    //事假 需调整
+                                typeName = "事假";
+                                if (sp_leave.timeunit == 0) //半天
+                                {
+                                    meal_deduction += 10;
+                                    personalLeaveTotal += dailyWage / 2;
+                                }
+                                else if (sp_leave.timeunit == 1) //小时
+                                {
+                                    if (sp_leave.duration >= 3 && sp_leave.duration <= 7.5) //7.5小时 一天
+                                    {
+                                        meal_deduction += 10;
+                                    }
+                                    else if (sp_leave.duration > 7.5)
+                                    {
+                                        decimal daysPrice = Convert.ToDecimal(sp_leave.duration / 7.5 * 10);
+                                        meal_deduction += daysPrice;
+                                    }
+                                }
+                                break;
+                            case 3:    //病假 需调整
+                                typeName = "病假";
+                                if (sp_leave.timeunit == 0) //半天
+                                {
+                                    meal_deduction += 10;
+                                    sickLeaveTotal += sickLeave_deduction / 2;
+                                }
+                                else if (sp_leave.timeunit == 1) //小时
+                                {
+                                    if (sp_leave.duration >= 3 && sp_leave.duration <= 7.5) //7.5小时 一天
+                                    {
+                                        meal_deduction += 10;
+                                    }
+                                    else if (sp_leave.duration > 7.5)
+                                    {
+                                        decimal daysPrice = Convert.ToDecimal(sp_leave.duration / 7.5 * 10);
+                                        meal_deduction += daysPrice;
+                                    }
+                                }
+                                break;
+                            case 4:    //调休假
+                                typeName = "调休假";
+                                if (sp_leave.timeunit == 0) //半天
+                                {
+                                    meal_deduction += 10;
+                                }
+                                else if (sp_leave.timeunit == 1) //小时
+                                {
+                                    if (sp_leave.duration >= 3 && sp_leave.duration <= 7.5) //7.5小时 一天
+                                    {
+                                        meal_deduction += 10;
+                                    }
+                                    else if (sp_leave.duration > 7.5)
+                                    {
+                                        decimal daysPrice = Convert.ToDecimal(sp_leave.duration / 7.5 * 10);
+                                        meal_deduction += daysPrice;
+                                    }
+                                }
+                                break;
+                            case 5:    //婚假
+                                typeName = "婚假";
+                                if (sp_leave.timeunit == 0) //半天
+                                {
+                                    meal_deduction += 10;
+                                }
+                                else if (sp_leave.timeunit == 1) //小时
+                                {
+                                    if (sp_leave.duration >= 3 && sp_leave.duration <= 7.5) //7.5小时 一天
+                                    {
+                                        meal_deduction += 10;
+                                    }
+                                    else if (sp_leave.duration > 7.5)
+                                    {
+                                        decimal daysPrice = Convert.ToDecimal(sp_leave.duration / 7.5 * 10);
+                                        meal_deduction += daysPrice;
+                                    }
+                                }
+                                break;
+                            case 6:    //产假
+                                typeName = "产假";
+                                if (sp_leave.timeunit == 0) //半天
+                                {
+                                    meal_deduction += 10;
+                                }
+                                else if (sp_leave.timeunit == 1) //小时
+                                {
+                                    if (sp_leave.duration >= 3 && sp_leave.duration <= 7.5) //7.5小时 一天
+                                    {
+                                        meal_deduction += 10;
+                                    }
+                                    else if (sp_leave.duration > 7.5)
+                                    {
+                                        decimal daysPrice = Convert.ToDecimal(sp_leave.duration / 7.5 * 10);
+                                        meal_deduction += daysPrice;
+                                    }
+                                }
+                                break;
+                            case 7:    //陪产假
+                                typeName = "陪产假";
+                                if (sp_leave.timeunit == 0) //半天
+                                {
+                                    meal_deduction += 10;
+                                }
+                                else if (sp_leave.timeunit == 1) //小时
+                                {
+                                    if (sp_leave.duration >= 3 && sp_leave.duration <= 7.5) //7.5小时 一天
+                                    {
+                                        meal_deduction += 10;
+                                    }
+                                    else if (sp_leave.duration > 7.5)
+                                    {
+                                        decimal daysPrice = Convert.ToDecimal(sp_leave.duration / 7.5 * 10);
+                                        meal_deduction += daysPrice;
+                                    }
+                                }
+                                break;
+                            default:
+                                break;
+                        }
+
+                        Ex_Item ex_Item = new Ex_Item()
+                        {
+                            SubTypeId = sp_leave.leave_type,
+                            SubType = typeName,
+                            Start_time_dt = sp_leave.start_time_dt,
+                            End_time_dt = sp_leave.end_time_dt,
+                            Duration = sp_leave.duration,
+                            Reason = sp_leave.reason,
+                            Apply_time_dt = sp_item.apply_time_dt,
+                            Approval_name = sp_item.approval_name,
+                        };
+                        ex_ItemInfos.Add(ex_Item);
+                    }
+                }
+
+                if (ex_ItemInfos.Count > 0)
+                {
+                    ex_Items_jq.Ex_ItemInfo = ex_ItemInfos.OrderBy(it => it.SubTypeId).ThenBy(it => it.Start_time_dt).ToList();
+                    ex_Items.Add(ex_Items_jq);
+                }
+
+                #endregion
+
+                #endregion
+
+
+                #region 打卡补卡 处理
+
+                if (reissueCardNum == 3)
+                {
+                    reissuecard_deduction += 10;
+                }
+                else if (reissueCardNum >= 4)
+                {
+                    reissuecard_deduction += 50;
+                }
+
+                #endregion
+
+                Ex_Items ex_Items_dk = new Ex_Items() { Type = "打卡" };    //打卡
+                //List<Ex_Item> ex_reissuecard_Items = new List<Ex_Item>();
+                List<dynamic> ex_reissuecard_Items = new List<dynamic>();
+                List<Sp_Info> sp_reissuecard_item_InfosData = sp_reissuecard_InfosData.Where(it => it.apply_name == itemName).ToList();
+
+                #region 打卡异常处理 统计 1-迟到;2-早退;3-缺卡;4-旷工;5-地点异常;6-设备异常;
+
+                int beLateNum = 0,           // 1-迟到;
+                    leaveEarlyNum = 0,       // 2-早退;
+                    dummyDeckNum = 0,        // 3-缺卡;
+                    minerNum = 0,            // 4-旷工;
+                    locationAnomalyNum = 0,  // 5-地点异常;
+                    unitExNum = 0;           // 6-设备异常;
+
+                if (summary_Info.except_days > 0)
+                {
+                    List<Exception_Info>? ex_infos = checkInData.exception_infos;
+                    if (ex_infos != null && ex_infos.Count >= 0)
+                    {
+                        beLateNum = ExceptionStatistics(ex_infos, 1);
+                        leaveEarlyNum = ExceptionStatistics(ex_infos, 2);
+                        dummyDeckNum = ExceptionStatistics(ex_infos, 3);
+                        minerNum = ExceptionStatistics(ex_infos, 4);
+                        locationAnomalyNum = ExceptionStatistics(ex_infos, 5);
+                        unitExNum = ExceptionStatistics(ex_infos, 6);
+                    }
+                }
+
+                foreach (Sp_Info sp_reissuecard_item in sp_reissuecard_item_InfosData)
+                {
+                    DateTime apply_time_dt = sp_reissuecard_item.apply_time_dt; //申请时间
+                    List<string>? approval_name = sp_reissuecard_item.approval_name; //审核人
+
+                    Comm sp_comm = sp_reissuecard_item.comm;
+                    if (sp_comm != null)
+                    {
+                        if (sp_comm.applydata != null)
+                        {
+                            List<ApplyInfo> applyInfos = sp_comm.applydata;
+                            if (applyInfos.Count > 0)
+                            {
+                                //Ex_Item ex_reissuecard_Item = new Ex_Item();
+                                dynamic ex_reissuecard_Item = null;
+                                string text = applyInfos.Where(it => it.type == "text").FirstOrDefault().value.ToString(); //异常状态
+                                DateTime? datehour = applyInfos.Where(it => it.type == "datehour").FirstOrDefault().valueDt;//补卡时间
+                                string textarea = applyInfos.Where(it => it.type == "textarea").FirstOrDefault().value.ToString();//补卡事由
+                                if (text.Contains("未打卡"))
+                                {
+                                    ex_reissuecard_Item = new
+                                    {
+                                        SubTypeId = 0,
+                                        SubType = "未打卡",
+                                        title = text,
+                                        datehour = datehour == null ? "" : Convert.ToDateTime(datehour).ToString("yyyy-MM-dd HH:mm:ss"),
+                                        textarea = textarea,
+                                        apply_time_dt = apply_time_dt,
+                                        approval_name = approval_name
+                                    };
+                                }
+                                else if (text.Contains("迟到"))
+                                {
+                                    ex_reissuecard_Item = new
+                                    {
+                                        SubTypeId = 1,
+                                        SubType = "迟到",
+                                        title = text,
+                                        datehour = datehour == null ? "" : Convert.ToDateTime(datehour).ToString("yyyy-MM-dd HH:mm:ss"),
+                                        textarea = textarea,
+                                        apply_time_dt = apply_time_dt,
+                                        approval_name = approval_name
+                                    };
+                                }
+                                else if (text.Contains("早退"))
+                                {
+                                    ex_reissuecard_Item = new
+                                    {
+                                        SubTypeId = 2,
+                                        SubType = "早退",
+                                        title = text,
+                                        datehour = datehour == null ? "" : Convert.ToDateTime(datehour).ToString("yyyy-MM-dd HH:mm:ss"),
+                                        textarea = textarea,
+                                        apply_time_dt = apply_time_dt,
+                                        approval_name = approval_name
+                                    };
+                                }
+                                else if (text.Contains("缺卡"))
+                                {
+                                    ex_reissuecard_Item = new
+                                    {
+                                        SubTypeId = 3,
+                                        SubType = "缺卡",
+                                        title = text,
+                                        datehour = datehour == null ? "" : Convert.ToDateTime(datehour).ToString("yyyy-MM-dd HH:mm:ss"),
+                                        textarea = textarea,
+                                        apply_time_dt = apply_time_dt,
+                                        approval_name = approval_name
+                                    };
+                                }
+                                else if (text.Contains("旷工"))
+                                {
+                                    ex_reissuecard_Item = new
+                                    {
+                                        SubTypeId = 4,
+                                        SubType = "旷工",
+                                        title = text,
+                                        datehour = datehour == null ? "" : Convert.ToDateTime(datehour).ToString("yyyy-MM-dd HH:mm:ss"),
+                                        textarea = textarea,
+                                        apply_time_dt = apply_time_dt,
+                                        approval_name = approval_name
+                                    };
+                                }
+                                else if (text.Contains("地点异常"))
+                                {
+                                    ex_reissuecard_Item = new
+                                    {
+                                        SubTypeId = 5,
+                                        SubType = "地点异常",
+                                        title = text,
+                                        datehour = datehour == null ? "" : Convert.ToDateTime(datehour).ToString("yyyy-MM-dd HH:mm:ss"),
+                                        textarea = textarea,
+                                        apply_time_dt = apply_time_dt,
+                                        approval_name = approval_name
+                                    };
+                                }
+                                else if (text.Contains("设备异常"))
+                                {
+                                    ex_reissuecard_Item = new
+                                    {
+                                        SubTypeId = 6,
+                                        SubType = "设备异常",
+                                        title = text,
+                                        datehour = datehour == null ? "" : Convert.ToDateTime(datehour).ToString("yyyy-MM-dd HH:mm:ss"),
+                                        textarea = textarea,
+                                        apply_time_dt = apply_time_dt,
+                                        approval_name = approval_name
+                                    };
+                                }
+                                if (ex_reissuecard_Item != null)
+                                {
+                                    ex_reissuecard_Items.Add(ex_reissuecard_Item);
+                                }
+                            }
+                        }
+                    }
+                }
+
+                if (ex_reissuecard_Items.Count > 0)
+                {
+                    ex_Items_dk.Ex_ItemInfo = ex_reissuecard_Items.OrderBy(it => it.SubTypeId).ThenBy(it => it.datehour).ToList();
+                    ex_Items.Add(ex_Items_dk);
+                }
+
+                #endregion
+
+
+                #region 应发合计 实发合计 扣款合计(假勤扣款,其他扣款,社保扣款,公积金代扣,个税扣款)
+
+                decimal mealTotal = meal_subsidy - meal_deduction;  //餐补
+                decimal salaryTotal = amountPayable + mealTotal;    //应发合计
+
+                //扣款合计 不含个税
+                decimal eductionTotal = sickLeaveTotal + personalLeaveTotal + beLate_deduction + early_deduction + absenteeism_deduction + unprinted_deduction + other_deduction +
+                    pm_wsInfo.WithholdingInsurance + pm_wsInfo.ReservedFunds;
+                decimal actualReleaseTotal = salaryTotal - eductionTotal; //实发合计 * 不含个税
+
+
+                #endregion
+
+                #region 处理当月工资数据
+                pm_wsInfo.YearMonth = thisYearMonth;
+                pm_wsInfo.StartDate = startDt.ToString("yyyy-MM-dd");
+                pm_wsInfo.EndDate = endDt.ToString("yyyy-MM-dd");
+
+                pm_wsInfo.SickLeave = sickLeaveTotal;           //病假
+                pm_wsInfo.SomethingFalse = personalLeaveTotal;  //事假
+                pm_wsInfo.LateTo = beLate_deduction;            //迟到
+                pm_wsInfo.LeaveEarly = early_deduction;         //早退
+                pm_wsInfo.Absenteeism = absenteeism_deduction;  //旷工
+                pm_wsInfo.NotPunch = unprinted_deduction;       //未打卡
+                pm_wsInfo.OtherDeductions = other_deduction;    //其他
+                pm_wsInfo.Ex_ItemsRemark = JsonConvert.SerializeObject(ex_Items);  //
+                pm_wsInfo.Mealsupplement = mealTotal;          //餐补
+
+                pm_wsInfo.Should = salaryTotal;            //应发合计
+                pm_wsInfo.TotalDeductions = eductionTotal; //扣款合计
+                pm_wsInfo.TotalRealHair = actualReleaseTotal; //实发合计
+                pm_wsInfo.AfterTax = actualReleaseTotal - pm_wsInfo.WithholdingTax; //税后工资
+
+                pm_wsInfo.LastUpdateUserId = userId;
+                pm_wsInfo.LastUpdateDt = DateTime.Now;
+                pm_wsInfo.CreateUserId = userId;
+                pm_wsInfo.CreateTime = DateTime.Now;
+                pm_wsInfo.DeleteUserId = null;
+                pm_wsInfo.DeleteTime = null;
+                #endregion
+
+            }
+            _result.Code = 0;
+            _result.Data = pm_WageSheetDattaSources;
+
+            return _result;
+        }
+
+
+        /// <summary>
+        /// 打卡数据
+        /// 假勤数据 统计
+        /// </summary>
+        /// <param name="datas">数据源</param>
+        /// <param name="type">
+        /// 1-请假;2-补卡;3-出差;4-外出;100-外勤;
+        /// </param>
+        /// <param name="subTypeName">
+        /// 年假 事假 病假 调休假 婚嫁 产假  陪产假 丧假 补卡次数 出差 外出数 外勤 其他
+        /// </param>
+        /// <returns></returns>
+        private static int Fallibilitydispose(List<Sp_Item> datas, int type, string? subTypeName)
+        {
+            int num = 0;
+
+            Sp_Item _Info = datas.Where(it => it.type == type && it.name == subTypeName).FirstOrDefault();
+            if (_Info != null) { num = _Info.count; }
+
+            return num;
+        }
+
+        /// <summary>
+        /// 打卡数据
+        /// 异常数据 统计
+        /// </summary>
+        /// <returns></returns>
+        private static int ExceptionStatistics(List<Exception_Info> datas, int type)
+        {
+            int num = 0;
+
+            Exception_Info _Info = datas.Where(it => it.exception == type).FirstOrDefault();
+            if (_Info != null) { num = _Info.count; }
+
+            return num;
+        }
+
+    }
+}

+ 7 - 0
OASystem/OASystem.Api/OAMethodLib/QiYeWeChatAPI/IQiYeWeChatApiService.cs

@@ -43,5 +43,12 @@ namespace OASystem.API.OAMethodLib.QiYeWeChatAPI
         /// <returns></returns>
         Task<ApprovalDataView> GetApprovalDataAsync(DateTime startDt, DateTime endDt);
 
+        /// <summary>
+        /// 获取审批数据(旧)(redis缓存)
+        /// </summary>
+        /// <param name="startDt"></param>
+        /// <param name="endDt"></param>
+        /// <returns></returns>
+        Task<List<Sp_Info>> GetApprovalDataRedisAsync(DateTime startDt, DateTime endDt);
     }
 }

+ 64 - 6
OASystem/OASystem.Api/OAMethodLib/QiYeWeChatAPI/QiYeWeChatApiService.cs

@@ -292,7 +292,7 @@ namespace OASystem.API.OAMethodLib.QiYeWeChatAPI
         #region 打卡
 
         /// <summary>
-        /// 获取月打卡数据
+        /// 获取月打卡数据(redis缓存)
         /// </summary>
         /// <param name="startDt"></param>
         /// <param name="endDt"></param>
@@ -355,11 +355,15 @@ namespace OASystem.API.OAMethodLib.QiYeWeChatAPI
                 new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
 
 
-            TimeSpan ts = DateTime.Now.AddMinutes(60) - DateTime.Now; //设置redis 过期时间 60分钟
-            await RedisRepository
-                .RedisFactory
-                .CreateRedisRepository()
-                .StringSetAsync<string>("Checkin_MonthData", JsonConvert.SerializeObject(checkInView), ts);//List<T> 存
+            if (checkInView.errcode == 0)
+            {
+                TimeSpan ts = DateTime.Now.AddMinutes(60) - DateTime.Now; //设置redis 过期时间 60分钟
+                await RedisRepository
+                    .RedisFactory
+                    .CreateRedisRepository()
+                    .StringSetAsync<string>("Checkin_MonthData", JsonConvert.SerializeObject(checkInView), ts);//List<T> 存
+            }
+           
 
             return checkInView;
         }
@@ -438,6 +442,60 @@ namespace OASystem.API.OAMethodLib.QiYeWeChatAPI
             return approvalDataView;
         }
 
+
+        /// <summary>
+        /// 获取审批数据(旧)(redis缓存)
+        /// </summary>
+        /// <param name="startDt"></param>
+        /// <param name="endDt"></param>
+        /// <returns></returns>
+        public async Task<List<Sp_Info>> GetApprovalDataRedisAsync(DateTime startDt, DateTime endDt)
+        {
+            List<Sp_Info> sp_Infos = new List<Sp_Info>();
+
+            //获取所有打卡补卡,审批 数据 前后范围增加10天
+            DateTime sp_startDt = startDt.AddDays(-10);
+            DateTime sp_centerDt = sp_startDt.AddDays(30);
+            DateTime sp_endDt = endDt.AddDays(10);
+
+
+            string redisName = "ApprovalData_" + sp_startDt.Year + "_" + sp_startDt.Month;
+            string sp_InfosString = await RedisRepository.RedisFactory
+                                            .CreateRedisRepository()
+                                            .StringGetAsync<string>(redisName);//string 取
+            if (string.IsNullOrEmpty(sp_InfosString))
+            {
+                ApprovalDataView approvalData_1 = await GetApprovalDataAsync(sp_startDt, sp_centerDt);  //时间段内所有 审批数据
+                ApprovalDataView approvalData_2 = await GetApprovalDataAsync(sp_centerDt, sp_endDt);    //时间段内所有 审批数据
+                if (approvalData_1.errcode != 0)
+                {
+                    Log.Error("企业微信 获取 "+ sp_startDt + " - "+ sp_centerDt + " 内审批 Msg:" + approvalData_1.errmsg);
+
+                    return sp_Infos;
+                }
+                sp_Infos.AddRange(approvalData_1.data);
+                if (approvalData_2.errcode != 0)
+                {
+                    Log.Error("企业微信 获取 "+ sp_centerDt + " - "+ sp_endDt + " 内审批 Msg:" + approvalData_2.errmsg);
+
+                    return sp_Infos;
+                }
+                sp_Infos.AddRange(approvalData_2.data);
+
+                TimeSpan ts = DateTime.Now.AddMinutes(60) - DateTime.Now; //设置redis 过期时间 60分钟
+                await RedisRepository
+                    .RedisFactory
+                    .CreateRedisRepository()
+                    .StringSetAsync<string>(redisName, JsonConvert.SerializeObject(sp_Infos), ts);//string 存
+            }
+            else
+            {
+                sp_Infos = JsonConvert.DeserializeObject<List<Sp_Info>>(sp_InfosString);
+            }
+
+            return sp_Infos;
+        }
+
         #endregion
     }
 }

+ 3 - 0
OASystem/OASystem.Domain/AutoMappers/_baseMappingProfile.cs

@@ -213,6 +213,9 @@ namespace OASystem.Domain.AutoMappers
             CreateMap<Pm_WageSheet, WageSheetItemInfoView>();
             CreateMap<WageAddOrEditDto, Pm_WageSheet>();
             CreateMap<WageSheetInfos, Pm_WageSheet>();
+            CreateMap<SalaryCalculatorSingleDto, Pm_WageSheet>();
+            CreateMap<Pm_WageSheet, WageSheetInfoView>();
+            
             #endregion
         }
     }

+ 92 - 0
OASystem/OASystem.Domain/Dtos/PersonnelModule/WageSheetDto.cs

@@ -246,4 +246,96 @@ namespace OASystem.Domain.Dtos.PersonnelModule
         /// </summary>
         public string? yearMonth { get; set; }
     }
+
+    /// <summary>
+    /// 计算工资 单个 Dto
+    /// </summary>
+    public class SalaryCalculatorSingleDto
+    {
+        /// <summary>
+        /// 用户Id
+        /// </summary>
+        public int UserId { get; set; }
+
+        /// <summary>
+        /// 年月
+        /// </summary>
+        public string? YearMonth { get; set; }
+
+        /// <summary>
+        /// 工资日期 起
+        /// </summary>
+        public string? StartDate { get; set; }
+
+        /// <summary>
+        /// 工资日期 止
+        /// </summary>
+        public string? EndDate { get; set; }
+
+        /// <summary>
+        /// 基本工资
+        /// </summary>
+        public decimal Basic { get; set; }
+
+        /// <summary>
+        /// 绩效工资
+        /// </summary>
+        public decimal Floats { get; set; }
+
+        /// <summary>
+        /// 岗位津贴
+        /// </summary>
+        public decimal PostAllowance { get; set; }
+
+        /// <summary>
+        /// 服装洗理补贴
+        /// </summary>
+        public decimal GarmentWashSubsidies { get; set; }
+
+        /// <summary>
+        /// 通讯补贴
+        /// </summary>
+        public decimal CommunicationSubsidies { get; set; }
+
+        /// <summary>
+        /// 交通补贴
+        /// </summary>
+        public decimal TrafficSubsidies { get; set; }
+
+        /// <summary>
+        /// 保密费
+        /// </summary>
+        public decimal InformationSecurityFee { get; set; }
+
+        /// <summary>
+        /// 操作奖金
+        /// </summary>
+        public decimal OperationBonus { get; set; }
+
+        /// <summary>
+        /// 特殊津贴
+        /// </summary>
+        public decimal SpecialAllowance { get; set; }
+
+        /// <summary>
+        /// 其他补贴
+        /// </summary>
+        public decimal OtherSubsidies { get; set; }
+
+        /// <summary>
+        /// 代扣保险
+        /// </summary>
+        public decimal WithholdingInsurance { get; set; }
+
+        /// <summary>
+        /// 餐补
+        /// </summary>
+        public decimal Mealsupplement { get; set; }
+
+        /// <summary>
+        /// 部门集体团建费
+        /// </summary>
+        public decimal GroupCost { get; set; }
+
+    }
 }

+ 5 - 0
OASystem/OASystem.Domain/ViewModels/PersonnelModule/WageSheetView.cs

@@ -156,6 +156,11 @@ namespace OASystem.Domain.ViewModels.PersonnelModule
         /// </summary>
         public decimal OtherDeductions { get; set; }
 
+        /// <summary>
+        /// 考勤/打卡 详情
+        /// </summary>
+        public string Ex_ItemsRemark { get; set; }
+
         /// <summary>
         /// 应发合计
         /// </summary>