package service import ( "context" "errors" "fmt" "github.com/fonchain_enterprise/fonchain-main/api/account" "github.com/fonchain_enterprise/fonchain-main/api/oa" "github.com/fonchain_enterprise/fonchain-main/api/rule" "github.com/fonchain_enterprise/fonchain-main/pkg/e" "github.com/fonchain_enterprise/fonchain-main/pkg/model/login" "github.com/fonchain_enterprise/fonchain-main/pkg/model/oa_model" "github.com/fonchain_enterprise/fonchain-main/pkg/service/oa_new/common" "github.com/fonchain_enterprise/fonchain-main/pkg/utils/holiday" "github.com/gin-gonic/gin" "github.com/jinzhu/copier" "math" "strconv" "strings" "time" ) // WorkingTimeBest // 生成 最优 考勤班次 针对 特殊员工 func WorkingTimeBest(staffUID uint64, in []oa_model.QueryTimeOption) (bestOptions []*oa_model.TimeOption, err error) { /* 多个部门 组合 最优 考勤班次 9:00 17:00 10:00 18:00 => 10:00 17:00 */ if in == nil { in = make([]oa_model.QueryTimeOption, 0) in, err = MakeQueryTimeOption(staffUID) if err != nil { return bestOptions, err } } timesMap := make(map[int][]*oa_model.TimeOption, 0) for i := 0; i < len(in); i++ { res, _, _ := WorkingTimeSetting(in[i]) // 如果 考勤规则 为 空 则跳过 if len(res) == 0 { continue } /* 比较 打卡次数 一致的 班次规则 */ v, isExist := timesMap[len(res)] if isExist { /* 打卡 次数 一致 判断 时间点 先后 宗旨 上班晚 下班早 */ for i := 0; i < len(v); i++ { oldOnWorkTime := "2006-01-02 " + v[i].OnWorkTime + ":00" newOnWorkTime := "2006-01-02 " + res[i].OnWorkTime + ":00" oldOnWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", oldOnWorkTime, time.Local) newOnWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", newOnWorkTime, time.Local) if err == nil && newOnWorkTimeF.After(oldOnWorkTimeF) { v[i].OnWorkTime = res[i].OnWorkTime } oldOffWorkTime := "2006-01-02 " + v[i].OffWorkTime + ":00" newOffWorkTime := "2006-01-02 " + res[i].OffWorkTime + ":00" oldOffWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", oldOffWorkTime, time.Local) newOffWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", newOffWorkTime, time.Local) if err == nil && newOffWorkTimeF.Before(oldOffWorkTimeF) { v[i].OffWorkTime = res[i].OffWorkTime } } } else { timesMap[len(res)] = res } } // 至此 已筛选出 每一类 打卡次数 的 最优 时间 bestOptions = make([]*oa_model.TimeOption, 0) if len(timesMap) == 1 { for _, v := range timesMap { bestOptions = v } return bestOptions, nil } // 判断 是否存在 两次 打卡 // 默认 两次 打卡 为 最优打卡次数 其次 四次 以此类推 currentBestClockInNum := 9999 for k, v := range timesMap { if currentBestClockInNum > k { currentBestClockInNum = k bestOptions = v } } // 当前 默认 只有 两次 或者 四次 // 注: 超过 四次 不适用 for k, v := range timesMap { if k == currentBestClockInNum { continue } for i := 0; i < k; { oldOnWorkTime := "2006-01-02 " + bestOptions[i].OnWorkTime + ":00" newOnWorkTime := "2006-01-02 " + v[i].OnWorkTime + ":00" oldOnWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", oldOnWorkTime, time.Local) newOnWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", newOnWorkTime, time.Local) if err == nil && newOnWorkTimeF.After(oldOnWorkTimeF) { bestOptions[i].OnWorkTime = v[i].OnWorkTime } oldOffWorkTime := "2006-01-02 " + bestOptions[i].OffWorkTime + ":00" newOffWorkTime := "2006-01-02 " + v[i+1].OffWorkTime + ":00" oldOffWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", oldOffWorkTime, time.Local) newOffWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", newOffWorkTime, time.Local) if err == nil && newOffWorkTimeF.Before(oldOffWorkTimeF) { bestOptions[i].OffWorkTime = v[i+1].OffWorkTime } i = k } } for i := 0; i < len(bestOptions); i++ { fmt.Printf("%+v\n", bestOptions[i]) } return bestOptions, nil } // WorkingTimeBestV1 // 生成 最优 考勤班次 针对 特殊员工 func WorkingTimeBestV1(c *gin.Context, in []oa_model.QueryTimeOption) (times []*oa_model.TimeOption, err error) { /* 多个部门 组合 最优 考勤班次 9:00 17:00 10:00 18:00 => 10:00 17:00 */ timesMap := make(map[int][]*oa_model.TimeOption, 0) for i := 0; i < len(in); i++ { res, _, err := WorkingTimeSetting(in[i]) if err != nil { return nil, err } /* 比较 打卡次数 一致的 班次规则 */ v, isExist := timesMap[len(res)] if isExist { /* 打卡 次数 一致 判断 时间点 先后 宗旨 上班晚 下班早 */ for i := 0; i < len(v); i++ { oldOnWorkTime := "2006-01-02 " + v[i].OnWorkTime + ":00" newOnWorkTime := "2006-01-02 " + res[i].OnWorkTime + ":00" oldOnWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", oldOnWorkTime, time.Local) newOnWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", newOnWorkTime, time.Local) if err == nil && newOnWorkTimeF.After(oldOnWorkTimeF) { v[i].OnWorkTime = res[i].OnWorkTime } oldOffWorkTime := "2006-01-02 " + v[i].OffWorkTime + ":00" newOffWorkTime := "2006-01-02 " + res[i].OffWorkTime + ":00" oldOffWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", oldOffWorkTime, time.Local) newOffWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", newOffWorkTime, time.Local) if err == nil && newOffWorkTimeF.Before(oldOffWorkTimeF) { v[i].OffWorkTime = res[i].OffWorkTime } } } else { timesMap[len(res)] = res } } // 至此 已筛选出 每一类 打卡次数 的 最优 时间 bestOptions := make([]*oa_model.TimeOption, 0) if len(timesMap) == 1 { for _, v := range timesMap { bestOptions = v } return bestOptions, nil } // 判断 是否存在 两次 打卡 // 默认 两次 打卡 为 最优打卡次数 其次 四次 以此类推 currentBestClockInNum := 9999 for k, v := range timesMap { if currentBestClockInNum > k { currentBestClockInNum = k bestOptions = v } } for k, v := range timesMap { bestClockInIndex := 0 bestOnWorkTimeIsChange := false for i := 0; i < k; { if bestClockInIndex > currentBestClockInNum { return } if !bestOnWorkTimeIsChange { oldOnWorkTime := "2006-01-02 " + bestOptions[bestClockInIndex].OnWorkTime + ":00" newOnWorkTime := "2006-01-02 " + v[i].OnWorkTime + ":00" oldOnWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", oldOnWorkTime, time.Local) newOnWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", newOnWorkTime, time.Local) if err == nil && newOnWorkTimeF.After(oldOnWorkTimeF) { bestOptions[bestClockInIndex].OnWorkTime = v[i].OnWorkTime bestOnWorkTimeIsChange = true } } if k > currentBestClockInNum { i++ continue } oldOffWorkTime := "2006-01-02 " + bestOptions[bestClockInIndex].OffWorkTime + ":00" newOffWorkTime := "2006-01-02 " + v[i].OffWorkTime + ":00" oldOffWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", oldOffWorkTime, time.Local) newOffWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", newOffWorkTime, time.Local) if err == nil && newOffWorkTimeF.Before(oldOffWorkTimeF) { bestOptions[bestClockInIndex].OffWorkTime = v[i].OffWorkTime } bestClockInIndex++ } //if isBestOnWorkTime == "" { // isBestOnWorkTime = currentOnWorkTime //} else { // oldOnWorkTime := "2006-01-02 " + isBestOnWorkTime + ":00" // newOnWorkTime := "2006-01-02 " + currentOnWorkTime + ":00" // oldOnWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", oldOnWorkTime, time.Local) // newOnWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", newOnWorkTime, time.Local) // if err == nil && newOnWorkTimeF.After(oldOnWorkTimeF) { // isBestOnWorkTime = currentOnWorkTime // } //} // //if isBestOffWorkTime == "" { // isBestOffWorkTime = currentOffWorkTime //} else { // oldOffWorkTime := "2006-01-02 " + isBestOffWorkTime + ":00" // newOffWorkTime := "2006-01-02 " + currentOffWorkTime + ":00" // oldOffWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", oldOffWorkTime, time.Local) // newOffWorkTimeF, err := time.ParseInLocation("2006-01-02 15:04:05", newOffWorkTime, time.Local) // if err == nil && newOffWorkTimeF.Before(oldOffWorkTimeF) { // isBestOffWorkTime = currentOffWorkTime // } //} } //currentClockInNum := 0 //currentClockInRule := make([]*oaApi.TimeOption, 0) //for i, options := range timesMap { // if currentClockInNum == 0 { // currentClockInNum = i // currentClockInRule = options // } // if i < currentClockInNum { // currentClockInNum = i // currentClockInRule = options // } //} return bestOptions, nil } // WorkingTimeSetting // 获取 考勤班次设置 func WorkingTimeSetting(in oa_model.QueryTimeOption) (times []*oa_model.TimeOption, week string, err error) { timeOptions := new(oa.WorkingTimeListReq) timeOptions.DepartmentUID = in.DepartmentUID timeOptions.PositionUID = in.PositionUID timeOptions.InUse = oa_model.InUse timeOptions.Page = 1 timeOptions.PageSize = 9999 list, err := GrpcOAImpl.WorkingTimeList(context.Background(), timeOptions) if err != nil { return nil, "", nil } fmt.Println("WorkingTimeSetting department uid is = ==============================================") fmt.Println("department uid is :", timeOptions.DepartmentUID) fmt.Println("position uid is :", timeOptions.PositionUID) fmt.Println("WorkingTimeSetting department uid is = ==============================================") fmt.Println("WorkingTimeSetting timeOptions is = ==============================================") fmt.Printf("WorkingTimeSetting timeOptions is :%+v\n", list.Data) fmt.Println("WorkingTimeSetting timeOptions is = ==============================================") times = make([]*oa_model.TimeOption, 0) for i := 0; i < len(list.Data); i++ { for j := 0; j < len(list.Data[i].Time); j++ { times = append(times, &oa_model.TimeOption{ OnWorkTime: list.Data[i].Time[j].OnWorkTime, OffWorkTime: list.Data[i].Time[j].OffWorkTime, }) } week = list.Data[i].Week } return times, week, nil } func WorkingTimeWeek(in oa_model.QueryTimeOption) (list *oa.WorkingTimeListRes, err error) { timeOptions := new(oa.WorkingTimeListReq) timeOptions.DepartmentUID = in.DepartmentUID timeOptions.PositionUID = in.PositionUID timeOptions.InUse = oa_model.InUse timeOptions.Page = 1 timeOptions.PageSize = 9999 list, err = GrpcOAImpl.WorkingTimeList(context.Background(), timeOptions) if err != nil { return nil, err } fmt.Println("WorkingTimeWeek department uid is = ==============================================") fmt.Println("department uid is :", timeOptions.DepartmentUID) fmt.Println("position uid is :", timeOptions.PositionUID) fmt.Println("WorkingTimeWeek department uid is = ==============================================") fmt.Println("WorkingTimeWeek timeOptions is = ==============================================") fmt.Printf("WorkingTimeWeek timeOptions is :%+v\n", list.Data) fmt.Println("WorkingTimeWeek timeOptions is = ==============================================") return } // 获取 工作周期 ( 如果 开始周期 是 0 则不变 结束周期 是 0 则将 0 -> 7 ) func WorkingTimeWeekBest(queryTimeOptions []oa_model.QueryTimeOption) (startDay, endDay int, err error) { startDay, endDay = -1, -1 for i := 0; i < len(queryTimeOptions); i++ { list, err := WorkingTimeWeek(queryTimeOptions[i]) if err != nil { return 0, 0, errors.New(e.ErrConfirmweek) } if len(list.Data) == 0 { continue } inStartDay, inEndDay := -1, -1 for j := 0; j < len(list.Data); j++ { fmt.Println("===================== 打印 数据库 week ===================================") fmt.Printf("week info is : %+v\n", list.Data[j].Week) fmt.Printf("week info is : %+v\n", list.Data[j].IsWorkDay) fmt.Println("===================== 打印 数据库 week ===================================") if list.Data[j].Week == "" && list.Data[j].IsWorkDay == e.IsWorkDay { list.Data[j].Week = "1,5" } weekStr := strings.Split(list.Data[j].Week, ",") if len(weekStr) != 2 { return 0, 0, errors.New("考勤规则,week错误") } inInStartDay, err := strconv.Atoi(weekStr[0]) if err != nil { return 0, 0, err } inInEndDay, err := strconv.Atoi(weekStr[1]) if err != nil { return 0, 0, err } // 特别注意的点 起始位是 0 无需关注 if inInEndDay == 0 { inInEndDay = 7 } if j == 0 { inStartDay = inInStartDay inEndDay = inInEndDay } else { if inInStartDay >= inStartDay { inStartDay = inInStartDay } if inInEndDay <= inEndDay { inEndDay = inInEndDay } } } if inStartDay >= startDay { startDay = inStartDay } if endDay == -1 { endDay = inEndDay } if inEndDay <= endDay { endDay = inEndDay } } return } func WorkingTimeInWeek(currentDay, startDay, endDay int) bool { if startDay <= currentDay && currentDay <= endDay { return true } return false } func MakeQueryTimeOption(staffUID uint64) (option []oa_model.QueryTimeOption, err error) { rulesRequest := new(rule.RulesRequest) rulesRequest.AccountID = staffUID rulesRes, err := RuleProvider.UserInfo(context.Background(), rulesRequest) if err != nil { //logger.Error("查询岗位信息错误 ListByDid err", err) return option, err } for i := 0; i < len(rulesRes.PositionUsers); i++ { option = append(option, oa_model.QueryTimeOption{ PositionUID: strconv.FormatUint(rulesRes.PositionUsers[i].PositionID, 10), DepartmentUID: strconv.FormatUint(rulesRes.PositionUsers[i].DepartmentId, 10), }) } return } func HandleHourLeaveFive(originHour float64) float32 { var hour float64 hour = math.Floor(originHour / 1) if math.Mod(originHour, 1) >= 0.5 { hour = hour + 0.5 } return float32(hour) } func HandleHourLeaveASeat(originHour float64) float32 { var hour float64 if originHour > 0 && originHour < 0.1 { hour = 0.1 } else { //hour, _ = strconv.ParseFloat(strconv.FormatFloat(originHour-0.05, 'f', 1, 64), 10) hour, _ = strconv.ParseFloat(strconv.FormatFloat(originHour, 'f', 1, 64), 10) } return float32(hour) } func WorkingTimeAndWeekBest(staffUID uint64, in []oa_model.QueryTimeOption) (best *oa_model.TimeOptionBest, err error) { times, err := WorkingTimeBest(0, in) if err != nil { return best, err } fmt.Println("timeOptions is = ==============================================") fmt.Printf("timeOptions is :%+v\n", times) fmt.Println("timeOptions is = ==============================================") best = new(oa_model.TimeOptionBest) for i := 0; i < len(times); i++ { best.Times = append(best.Times, &oa_model.TimeOption{ OnWorkTime: times[i].OnWorkTime, OffWorkTime: times[i].OffWorkTime, }) } startDay, endDay, err := WorkingTimeWeekBest(in) if err != nil { return best, err } if startDay == 7 { startDay = 0 } if endDay == 7 { endDay = 0 } best.Week = strings.Join([]string{strconv.Itoa(startDay), strconv.Itoa(endDay)}, ",") return } // 婚假 func MaritalLeave(req *oa_model.CheckLeave, setting *oa.OaSettingRes) (res *oa_model.CheckLeaveRes, err error) { res = new(oa_model.CheckLeaveRes) res.OtherLeave.StartTime = req.StartTime // 判断 是否存在国假 startTime, _ := time.Parse("2006-01-02", req.StartTime) var i int32 = 1 next: respData, _ := holiday.GetSingleData(holiday.ConvertTime(startTime.Format("2006-01-02")), true) if respData.Type == 1 && respData.TypeDes != "休息日" && i <= 3 { // 节假日 i++ } else if respData.Type == 0 || (respData.Type == 1 && respData.TypeDes == "休息日") { // 工作日 || 休息日 i++ } startTime = startTime.AddDate(0, 0, 1) if i <= setting.Data[0].Value.MaritalLeaveBalance { goto next } //second: // endData, _ := holiday.GetSingleData(holiday.ConvertTime(startTime.Format("2006-01-02")), false) // if endData.Type == 1 { // startTime = startTime.AddDate(0, 0, 1) // goto second // } res.OtherLeave.EndTime = startTime.AddDate(0, 0, -1).Format("2006-01-02") res.CommonLeave.Total = float32(setting.Data[0].Value.MaritalLeaveBalance) return } func OtherLeave(startDate string, Days int, startM string) (endDate, endM string) { if startDate == "" || startM == "" { return "", "" } start, _ := time.Parse("2006-01-02", startDate) if startM == "上午" { endDate = start.AddDate(0, 0, Days-1).Format("2006-01-02") endM = "下午" } else if startM == "下午" { endDate = start.AddDate(0, 0, Days).Format("2006-01-02") endM = "上午" } return } // 余额 func BalanceLeave(workYear float32, enterDate string, nowTime time.Time, req *oa_model.CheckLeave, setting *oa.OaSettingRes, apply *oa.ApplyRecordRes, overTimeApply *oa.ApplyRecordRes, leaveApply *oa.LeaveApplyInfoRes) (res *oa_model.CheckLeaveRes, err error) { res = new(oa_model.CheckLeaveRes) switch req.ApplyType { case oa_model.TypeAnnualLeave: // 年假 /* 年假不在计算 */ /*for i := 0; i < len(setting.Data[0].Value.AnnualLeaveBalance); i++ { if workYear >= float32(setting.Data[0].Value.AnnualLeaveBalance[i].Start) && (setting.Data[0].Value.AnnualLeaveBalance[i].Start != 0 || setting.Data[0].Value.AnnualLeaveBalance[i].End == 0) { if workYear >= 2 { enterTime, _ := time.Parse("2006-01-02", enterDate) enterTime.AddDate(int(setting.Data[0].Value.AnnualLeaveBalance[i].Start), 0, 0) if !time.Date(nowTime.Year(), 1, 1, 0, 0, 0, 0, time.Local).Before(enterTime.AddDate(int(setting.Data[0].Value.AnnualLeaveBalance[i].Start), 0, 0)) { res.CommonLeave.Total = float32(setting.Data[0].Value.AnnualLeaveBalance[i].Days) } else { if i > 1 { res.CommonLeave.Total = float32(setting.Data[0].Value.AnnualLeaveBalance[i-1].Days) } } } else { enterDateTime, _ := time.Parse("2006-01-02", enterDate) if time.Now().Year()-enterDateTime.Year() >= 1 { if nowTime.Year()-enterDateTime.Year() >= 2 { res.CommonLeave.Total = float32(setting.Data[0].Value.AnnualLeaveBalance[0].Days) } else { currentYear := time.Date(time.Now().Year(), 12, 31, 0, 0, 0, 0, time.Local) res.CommonLeave.Total = float32(math.Floor(float64(currentYear.Sub(time.Date(currentYear.Year(), enterDateTime.Month(), enterDateTime.Day()-1, 0, 0, 0, 0, time.Local)).Hours()/24/365) * float64(5))) } } } } } for i := 0; i < len(apply.Data); i++ { res.CommonLeave.Used += apply.Data[i].Days } res.CommonLeave.Balance = res.CommonLeave.Total - res.CommonLeave.Used */ for i := 0; i < len(apply.Data); i++ { res.CommonLeave.Used += apply.Data[i].Days } res.CommonLeave.Balance = leaveApply.LeaveApply.LeaveBalance case oa_model.TypeParentalLeave: // 育儿假 if leaveApply != nil { //res.CommonLeave.Total = float32(leaveApply.LeaveApply.Total) //res.CommonLeave.Used = float32(leaveApply.LeaveApply.Total) - leaveApply.LeaveApply.LeaveBalance res.CommonLeave.Balance = leaveApply.LeaveApply.LeaveBalance } //for i := 0; i < len(apply.Data); i++ { // res.CommonLeave.Used += apply.Data[i].Days //} //res.CommonLeave.Balance = res.CommonLeave.Total - res.CommonLeave.Used case oa_model.TypeNursingLeave: // 独生子女护理假 if leaveApply != nil { //res.CommonLeave.Total = float32(leaveApply.LeaveApply.Total) //res.CommonLeave.Used = float32(leaveApply.LeaveApply.Total) - leaveApply.LeaveApply.LeaveBalance res.CommonLeave.Balance = leaveApply.LeaveApply.LeaveBalance } //for i := 0; i < len(apply.Data); i++ { // res.CommonLeave.Used += apply.Data[i].Days //} //res.CommonLeave.Balance = res.CommonLeave.Total - res.CommonLeave.Used case oa_model.TypeSick: // 病假 for i := 0; i < len(setting.Data[0].Value.SickBalance); i++ { if workYear >= float32(setting.Data[0].Value.SickBalance[i].Start) && workYear < float32(setting.Data[0].Value.SickBalance[i].End) { enterTime, _ := time.Parse("2006-01-02", enterDate) enterTime.AddDate(int(setting.Data[0].Value.SickBalance[i].Start), 0, 0) if !time.Date(nowTime.Year(), 1, 1, 0, 0, 0, 0, time.Local).Before(enterTime.AddDate(int(setting.Data[0].Value.SickBalance[i].Start), 0, 0)) { res.CommonLeave.Total = float32(setting.Data[0].Value.SickBalance[i].Days) } else { if i > 1 { res.CommonLeave.Total = float32(setting.Data[0].Value.SickBalance[i-1].Days) } } } else { res.CommonLeave.Total = float32(setting.Data[0].Value.SickBalance[i].Days) } } //for i := 0; i < len(apply.Data); i++ { // res.CommonLeave.Used += apply.Data[i].Days //} case oa_model.TypeDayOff: // 调休 for i := 0; i < len(overTimeApply.Data); i++ { res.CommonLeave.Total += overTimeApply.Data[i].Hours } for i := 0; i < len(apply.Data); i++ { res.CommonLeave.Used += apply.Data[i].Hours } res.CommonLeave.Balance = res.CommonLeave.Total - res.CommonLeave.Used case oa_model.TypeMaternityLeave: // 产假 res.CommonLeave.Total = float32(setting.Data[0].Value.MaternityLeaveBalance.BasicDays) if req.Dystocia == 1 { res.CommonLeave.Total += float32(setting.Data[0].Value.MaternityLeaveBalance.Dystocia) } if req.Children > 1 { res.CommonLeave.Total += float32(setting.Data[0].Value.MaternityLeaveBalance.OneMore * (req.Children - 1)) } for i := 0; i < len(apply.Data); i++ { res.CommonLeave.Used += apply.Data[i].Days } res.OtherLeave.StartTime = req.StartTime res.OtherLeave.StartM = req.M res.OtherLeave.EndTime, res.OtherLeave.EndM = OtherLeave(req.StartTime, int(res.CommonLeave.Total), req.M) case oa_model.TypeAbortLeave: // 流产假 for i := 0; i < len(setting.Data[0].Value.AbortLeaveBalance); i++ { if req.Month >= setting.Data[0].Value.AbortLeaveBalance[i].Start && req.Month <= setting.Data[0].Value.AbortLeaveBalance[i].End { res.CommonLeave.Total = float32(setting.Data[0].Value.AbortLeaveBalance[i].Days) } else if req.Month >= setting.Data[0].Value.AbortLeaveBalance[i].Start && setting.Data[0].Value.AbortLeaveBalance[i].End == 0 { res.CommonLeave.Total = float32(setting.Data[0].Value.AbortLeaveBalance[i].Days) } } for i := 0; i < len(apply.Data); i++ { res.CommonLeave.Used += apply.Data[i].Days } res.OtherLeave.StartTime = req.StartTime res.OtherLeave.StartM = req.M res.OtherLeave.EndTime, res.OtherLeave.EndM = OtherLeave(req.StartTime, int(res.CommonLeave.Total), req.M) case oa_model.TypePaternityLeave: // 陪产假 res.CommonLeave.Total = float32(setting.Data[0].Value.PaternityLeaveBalance) for i := 0; i < len(apply.Data); i++ { res.CommonLeave.Used += apply.Data[i].Days } res.OtherLeave.StartTime = req.StartTime res.OtherLeave.StartM = req.M res.OtherLeave.EndTime, res.OtherLeave.EndM = OtherLeave(req.StartTime, int(res.CommonLeave.Total), req.M) case oa_model.TypeMatingCheckLeave: // 孕检假 for i := 0; i < len(setting.Data[0].Value.MatingCheckLeaveBalance); i++ { if req.Month >= setting.Data[0].Value.MatingCheckLeaveBalance[i].Start && req.Month <= setting.Data[0].Value.MatingCheckLeaveBalance[i].End { res.CommonLeave.Total = float32(setting.Data[0].Value.MatingCheckLeaveBalance[i].Months) } else if req.Month >= setting.Data[0].Value.MatingCheckLeaveBalance[i].Start && setting.Data[0].Value.MatingCheckLeaveBalance[i].End == 0 { res.CommonLeave.Total = float32(setting.Data[0].Value.MatingCheckLeaveBalance[i].Weeks) } } for i := 0; i < len(apply.Data); i++ { res.CommonLeave.Used++ } res.CommonLeave.Balance = res.CommonLeave.Total - res.CommonLeave.Used // 暂时默认为 1 res.CommonLeave.Total = 1 res.OtherLeave.StartTime = req.StartTime res.OtherLeave.StartM = req.M res.OtherLeave.EndTime, res.OtherLeave.EndM = OtherLeave(req.StartTime, 1, req.M) //case oa_model.TypeFuneralLeave: // 丧假 // res.CommonLeave.Total = float32(setting.Data[0].Value.FuneralLeaveBalance) // res.OtherLeave.StartTime = req.StartTime // res.OtherLeave.StartM = req.M // res.OtherLeave.EndTime, res.OtherLeave.EndM = OtherLeave(req.StartTime, int(res.CommonLeave.Total), req.M) case oa_model.TypeMaritalLeave: // 婚假 res.CommonLeave.Total = float32(setting.Data[0].Value.MaritalLeaveBalance) for i := 0; i < len(apply.Data); i++ { res.CommonLeave.Used += apply.Data[i].Days } res.OtherLeave.StartTime = req.StartTime res.OtherLeave.StartM = req.M res.OtherLeave.EndTime, res.OtherLeave.EndM = OtherLeave(req.StartTime, int(res.CommonLeave.Total), req.M) case oa_model.TypeBreastFeedingLeave: // 哺乳假 res.CommonLeave.Total = float32(setting.Data[0].Value.BreastFeedingLeaveBalance) * 2 * float32(req.Children) for i := 0; i < len(apply.Data); i++ { res.CommonLeave.Used += apply.Data[i].Hours } res.CommonLeave.Balance = res.CommonLeave.Total - res.CommonLeave.Used } return } func CheckLeaveHandle(checkLeaveReq *oa_model.CheckLeave, userInfo login.Info, forMoney bool) (res *oa_model.CheckLeaveRes, err error) { accountInfoReq := new(account.InfoRequest) accountInfoReq.ID = userInfo.ID // 工作年限 accountInfoRes, err := AccountProvider.Info(context.Background(), accountInfoReq) if err != nil { return } // 设置查询 oaSettingReq := new(oa.OaSettingReq) oaSettingRes := new(oa.OaSettingRes) keyword := oa_model.SettingKeyWordMap[checkLeaveReq.ApplyType] if keyword != "" { oaSettingReq.Keyword = keyword oaSettingRes, err = GrpcOAImpl.QueryOaSetting(context.Background(), oaSettingReq) if err != nil || len(oaSettingRes.Data) != 1 { //service.ResponseMsg(c, e.SUCCESS, serializer.Response{ // Msg: e.ERR_QUERY_OA_SETTING, // Status: e.Failed, //}) return res, errors.New(e.ErrQueryOaSetting) } } else if checkLeaveReq.ApplyType != oa_model.TypeDayOff { //service.ResponseMsg(c, e.SUCCESS, serializer.Response{ // Msg: e.ERR_NOT_NEED_BALANCE, // Status: e.Ok, //}) //return res, errors.New(e.ERR_NOT_NEED_BALANCE) return res, nil } // 申请请假查询 nowTime := time.Now() var StartTime time.Time var year string var month string if checkLeaveReq.StartTime != "" { StartTime, _ = time.Parse("2006-01-02", checkLeaveReq.StartTime) year = StartTime.Format("2006") month = common.CurrentMonth() + "-25" } else { year = nowTime.Format("2006") month = common.CurrentMonth() + "-25" } // 特殊处理 调休 if checkLeaveReq.ApplyType == oa_model.TypeDayOff && !forMoney { res = new(oa_model.CheckLeaveRes) var checkDayOffBalanceErr error res.CommonLeave.Balance, checkDayOffBalanceErr = CheckDayOffBalance(userInfo.ID) if checkDayOffBalanceErr != nil { return nil, checkDayOffBalanceErr } return res, nil } applyReq := new(oa.ApplyRecordReq) applyReq.StaffUID = userInfo.ID applyReq.ApplyType = []string{checkLeaveReq.ApplyType} applyReq.ApplyStatus = []int32{e.ApprovalWorkStatusDoing, e.ApprovalWorkStatusOk, e.ApprovalWorkStatusRevoking} applyReq.Page = 1 applyReq.PageSize = 9999 applyRes := new(oa.ApplyRecordRes) overTimeApply := new(oa.ApplyRecordRes) if checkLeaveReq.ApplyType == oa_model.TypeParentalLeave || checkLeaveReq.ApplyType == oa_model.TypeAnnualLeave || checkLeaveReq.ApplyType == oa_model.TypeNursingLeave || checkLeaveReq.ApplyType == oa_model.TypeSick { applyReq.BeginTime = year + "-01-01" applyReq.EndTime = year + "-12-31" } else if checkLeaveReq.ApplyType == oa_model.TypeDayOff { dates := holiday.SplitMonthV1(month, "2006-01-02") applyReq.BeginTime = dates[0] applyReq.EndTime = dates[len(dates)-1] overTimeApplyReq := new(oa.ApplyRecordReq) _ = copier.CopyWithOption(&overTimeApplyReq, applyReq, copier.Option{DeepCopy: true}) overTimeApplyReq.ApplyStatus = []int32{e.ApprovalWorkStatusOk} overTimeApplyReq.ApplyType = []string{oa_model.TypeOverTime} overTimeApplyReq.BeginTime = dates[0] overTimeApplyReq.EndTime = dates[len(dates)-1] overTimeApply, err = GrpcOAImpl.QueryOaApply(context.Background(), overTimeApplyReq) if err != nil { return nil, errors.New(e.ErrQueryOaApply) } for i := 0; i < len(overTimeApply.Data); i++ { if !CheckDateInMonth(overTimeApply.Data[i].ApplyTimes[0].Date, dates) { overTimeApply.Data = append(overTimeApply.Data[:i], overTimeApply.Data[i+1:]...) } } } else if checkLeaveReq.ApplyType == oa_model.TypeMatingCheckLeave { for i := 0; i < len(oaSettingRes.Data[0].Value.MatingCheckLeaveBalance); i++ { if checkLeaveReq.Month >= oaSettingRes.Data[0].Value.MatingCheckLeaveBalance[i].Start && checkLeaveReq.Month <= oaSettingRes.Data[0].Value.MatingCheckLeaveBalance[i].End { dates := holiday.SplitMonthV1(month, "2006-01-02") applyReq.BeginTime = dates[0] applyReq.EndTime = dates[len(dates)-1] } else if checkLeaveReq.Month >= oaSettingRes.Data[0].Value.MatingCheckLeaveBalance[i].Start && oaSettingRes.Data[0].Value.MatingCheckLeaveBalance[i].End == 0 { applyReq.BeginTime, applyReq.EndTime = holiday.CurrentWeek(StartTime) } } } else if checkLeaveReq.ApplyType == oa_model.TypeBreastFeedingLeave { currentDate := nowTime.Format("2006-01-02") if checkLeaveReq.StartTime != "" { currentDate = checkLeaveReq.StartTime } applyReq.BeginTime = currentDate applyReq.EndTime = currentDate } fmt.Println("========= applyReq 1 ========================= ") fmt.Printf("=== %+v\n", applyReq) fmt.Println("========= applyReq 2 ========================= ") applyRes, err = GrpcOAImpl.QueryOaApply(context.Background(), applyReq) if err != nil { return nil, errors.New(e.ErrQueryOaApply) } fmt.Println("========= QueryOaApply 1 ========================= ") fmt.Printf("=== %+v\n", applyRes.Data) fmt.Println("========= QueryOaApply 2 ========================= ") // 查询余额申请 育儿假 独生子女护理假 /* 丢弃 2025-01-06 */ /* leaveApplyRes := new(oa.LeaveApplyInfoRes) if checkLeaveReq.ApplyType == oa_model.TypeParentalLeave || checkLeaveReq.ApplyType == oa_model.TypeNursingLeave { leaveApplyReq := new(oa.LeaveApplyInfoReq) leaveApplyReq.StaffUID = userInfo.ID leaveApplyReq.LeaveApplyType = e.CheckLeaveApplyMap[checkLeaveReq.ApplyType] leaveApplyReq.IsOver = e.IsNotOver leaveApplyReq.UsefulTime = year leaveApplyRes, err = GrpcOAImpl.QueryLeaveApplyInfo(context.Background(), leaveApplyReq) if err != nil { if err.Error() == e.ErrNotHaveBalance { return nil, err } else { return nil, errors.New(e.ErrQueryOaLeaveApply) } } }*/ leaveApplyRes := new(oa.LeaveApplyInfoRes) leaveApplyRes.LeaveApply = new(oa.LeaveApply) if checkLeaveReq.ApplyType == oa_model.TypeParentalLeave || checkLeaveReq.ApplyType == oa_model.TypeNursingLeave || checkLeaveReq.ApplyType == oa_model.TypeAnnualLeave { var leaveBalanceInfoReq *oa.LeaveBalanceInfoReq var leaveBalanceInfoRes *oa.LeaveBalance leaveBalanceInfoReq = new(oa.LeaveBalanceInfoReq) leaveBalanceInfoReq.StaffUID = userInfo.ID yearInt, _ := strconv.Atoi(year) leaveBalanceInfoReq.Year = int32(yearInt) leaveBalanceInfoRes, err = GrpcOAImpl.GetLeaveBalanceInfo(context.Background(), leaveBalanceInfoReq) if err != nil { return nil, err } if leaveBalanceInfoRes != nil { if checkLeaveReq.ApplyType == oa_model.TypeParentalLeave { if leaveBalanceInfoRes.ParentalLeave > 0 { leaveApplyRes.LeaveApply.LeaveBalance = leaveBalanceInfoRes.ParentalLeave } else { return nil, errors.New(e.ErrNoBalance) } } if checkLeaveReq.ApplyType == oa_model.TypeNursingLeave { if leaveBalanceInfoRes.NursingLeave > 0 { leaveApplyRes.LeaveApply.LeaveBalance = leaveBalanceInfoRes.NursingLeave } else { return nil, errors.New(e.ErrNoBalance) } } if checkLeaveReq.ApplyType == oa_model.TypeAnnualLeave { if leaveBalanceInfoRes.AnnualLeave > 0 { leaveApplyRes.LeaveApply.LeaveBalance = leaveBalanceInfoRes.AnnualLeave } else { return nil, errors.New(e.ErrNoBalance) } } } } // 婚假 暂时先不单独处理 //if req.ApplyType == oa_model.TypeMaritalLeave { // res, err = MaritalLeave(req, oaSettingRes) //} res, err = BalanceLeave(accountInfoRes.Info.WorkYear, accountInfoRes.Info.EnterDate, nowTime, checkLeaveReq, oaSettingRes, applyRes, overTimeApply, leaveApplyRes) // 育儿假 return } func VerifyTimeOrder(applyTimes []oa_model.ApplyTime) error { if len(applyTimes) != 2 { return errors.New(e.ErrApplyTime) } start, _ := time.ParseInLocation("2006-01-02", applyTimes[0].Date, time.Local) end, _ := time.ParseInLocation("2006-01-02", applyTimes[1].Date, time.Local) if !start.After(end) { if applyTimes[0].M != "" || applyTimes[1].M != "" { if start.Equal(end) { if applyTimes[0].M == "下午" && applyTimes[1].M == "上午" { return errors.New(e.ErrTimeOrder) } } return nil } if applyTimes[0].Hour != "" && applyTimes[1].Hour != "" { if start.Equal(end) { startTime, _ := time.ParseInLocation("2006-01-02 15:04:05", applyTimes[0].Date+" "+applyTimes[0].Hour+":00", time.Local) endTime, _ := time.ParseInLocation("2006-01-02 15:04:05", applyTimes[1].Date+" "+applyTimes[1].Hour+":00", time.Local) if startTime.After(endTime) { return errors.New(e.ErrTimeOrder) } } return nil } } return errors.New(e.ErrTimeOrder) } func CheckWifi(ip string) (isInWifi bool, err error) { req := new(oa.OaSettingReq) req.Keyword = e.ChickInWifi isInWifi = false res, err := GrpcOAImpl.QueryOaSetting(context.Background(), req) if err != nil { return isInWifi, err } if res.Data != nil { for i := 0; i < len(res.Data); i++ { for _, ipOpt := range res.Data[i].Value.ChickInWifiOptions.IP { if ip == ipOpt { isInWifi = true } } } } return isInWifi, err } // CheckDayOffBalance 统计 前两个月的 加班时间 和 调休时间 func CheckDayOffBalance(staffUID uint64) (balance float32, err error) { _, _, balance, err = checkSingleDayOffBalance(staffUID, common.CurrentMonth()) return balance, err } // checkSingleDayOffBalance 统计单个月的加班时间和调休时间 // 截止至 2024-12 func checkSingleDayOffBalance(staffUID uint64, inMonth string) (overTime float32, dayOff float32, balance float32, err error) { dates := make([]string, 0) var month string if len(strings.Split(inMonth, "-")) == 2 { month = common.Add25ForMonth(inMonth) } else if len(strings.Split(inMonth, "-")) == 3 { month = inMonth } dates = holiday.SplitMonthV1(month, "2006-01-02") // 上个月 根据 传入的月份 获取上个月的月份 preMonth := common.PreMonth(inMonth) preMonth = common.Add25ForMonth(preMonth) preDates := holiday.SplitMonthV1(preMonth, "2006-01-02") // 加班时间 overTimeApplyReq := new(oa.ApplyRecordReq) overTimeApplyReq.StaffUID = staffUID overTimeApplyReq.ApplyType = []string{oa_model.TypeOverTime} overTimeApplyReq.ApplyStatus = []int32{e.ApprovalWorkStatusOk} overTimeApplyReq.Page = 1 overTimeApplyReq.PageSize = 9999 overTimeApplyReq.BeginTime = dates[0] overTimeApplyReq.EndTime = dates[len(dates)-1] overTimeApplyRes, overTimeApplyResErr := GrpcOAImpl.QueryOaApply(context.Background(), overTimeApplyReq) if overTimeApplyResErr != nil { return 0, 0, 0, overTimeApplyResErr } fmt.Println("========= overTimeApplyRes 1 ========================= ") fmt.Printf("month := %+v\n", month) fmt.Printf("=== %+v\n", overTimeApplyRes.Data) overTime = 0 for i := 0; i < len(overTimeApplyRes.Data); i++ { overTime += overTimeApplyRes.Data[i].Hours } fmt.Printf("=== overTime is :%+v\n", overTime) fmt.Println("========= overTimeApplyRes 2 ========================= ") // 调休时间 dayOffApplyReq := new(oa.ApplyRecordReq) dayOffApplyReq.StaffUID = staffUID dayOffApplyReq.ApplyType = []string{oa_model.TypeDayOff} dayOffApplyReq.ApplyStatus = []int32{e.ApprovalWorkStatusDoing, e.ApprovalWorkStatusOk, e.ApprovalWorkStatusRevoking} dayOffApplyReq.Page = 1 dayOffApplyReq.PageSize = 9999 dayOffApplyReq.BeginTime = dates[0] dayOffApplyReq.EndTime = dates[len(dates)-1] dayOffApplyRes, dayOffApplyResErr := GrpcOAImpl.QueryOaApply(context.Background(), dayOffApplyReq) if dayOffApplyResErr != nil { return 0, 0, 0, dayOffApplyResErr } fmt.Println("========= dayOffApplyRes 1 ========================= ") for i := 0; i < len(dayOffApplyRes.Data); i++ { dayOff += dayOffApplyRes.Data[i].Hours } fmt.Printf("=== dayOff is :%+v\n", dayOff) fmt.Println("========= dayOffApplyRes 2 ========================= ") retTime, _ := time.Parse("2006-01-02", dates[0]) pointTime, _ := time.Parse("2006-01-02", "2024-11-25") if retTime.Before(pointTime) { balance = float32(math.Floor(float64(overTime-dayOff)*10) / 10) fmt.Printf("retTime.Before(pointTime) \n === balance is :%+v\n", balance) return overTime, dayOff, balance, nil } var preBalance float32 // 上个月的 加班时间 preOverTimeApplyReq := new(oa.ApplyRecordReq) preOverTimeApplyReq.StaffUID = staffUID preOverTimeApplyReq.ApplyType = []string{oa_model.TypeOverTime} preOverTimeApplyReq.ApplyStatus = []int32{e.ApprovalWorkStatusOk} preOverTimeApplyReq.Page = 1 preOverTimeApplyReq.PageSize = 9999 preOverTimeApplyReq.BeginTime = preDates[0] preOverTimeApplyReq.EndTime = preDates[len(preDates)-1] preOverTimeApplyRes, preOverTimeApplyResErr := GrpcOAImpl.QueryOaApply(context.Background(), preOverTimeApplyReq) if preOverTimeApplyResErr != nil { return 0, 0, 0, preOverTimeApplyResErr } fmt.Println("========= pre overTimeApplyRes 1 ========================= ") fmt.Printf("preMonth := %+v\n", preMonth) fmt.Printf("=== %+v\n", overTimeApplyRes.Data) var preOverTime float32 = 0 for i := 0; i < len(preOverTimeApplyRes.Data); i++ { preOverTime += preOverTimeApplyRes.Data[i].Hours } fmt.Printf("=== preOverTime is :%+v\n", preOverTime) fmt.Println("========= pre overTimeApplyRes 2 ========================= ") // 上个月的 调休时间 preDayOffApplyReq := new(oa.ApplyRecordReq) preDayOffApplyReq.StaffUID = staffUID preDayOffApplyReq.ApplyType = []string{oa_model.TypeDayOff} preDayOffApplyReq.ApplyStatus = []int32{e.ApprovalWorkStatusDoing, e.ApprovalWorkStatusOk, e.ApprovalWorkStatusRevoking} preDayOffApplyReq.Page = 1 preDayOffApplyReq.PageSize = 9999 preDayOffApplyReq.BeginTime = preDates[0] preDayOffApplyReq.EndTime = preDates[len(preDates)-1] preDayOffApplyRes, preDayOffApplyResErr := GrpcOAImpl.QueryOaApply(context.Background(), preDayOffApplyReq) if preDayOffApplyResErr != nil { return 0, 0, 0, preDayOffApplyResErr } fmt.Println("========= pre dayOffApplyRes 1 ========================= ") var preDayOff float32 = 0 for i := 0; i < len(preDayOffApplyRes.Data); i++ { preDayOff += preDayOffApplyRes.Data[i].Hours } fmt.Printf("=== preDayOff is :%+v\n", preDayOff) fmt.Println("========= pre dayOffApplyRes 2 ========================= ") prePreMonth := common.PreMonth(preMonth) // 上上个月的 可用 _, _, prePreBalance, prePreBalanceErr := checkSingleDayOffBalance(staffUID, prePreMonth) if prePreBalanceErr != nil { return 0, 0, 0, prePreBalanceErr } fmt.Println("========= prePreBalance 1 ========================= ") fmt.Printf("=== prePreBalance is :%+v\n", prePreBalance) fmt.Println("========= prePreBalance 2 ========================= ") if prePreBalance-preDayOff > 0 { preBalance = preOverTime } else { preBalance = preOverTime + prePreBalance - preDayOff } fmt.Println("========= preBalance 1 ========================= ") fmt.Printf("=== preBalance is :%+v\n", preBalance) fmt.Println("========= preBalance 2 ========================= ") balance = overTime + preBalance - dayOff fmt.Println("========= balance 1 ========================= ") fmt.Printf("=== balance is :%+v\n", balance) fmt.Println("========= balance 2 ========================= ") return overTime, dayOff, balance, nil }