fonchain-fiee/pkg/service/oa_rule_handle.go
2025-02-19 14:24:15 +08:00

1132 lines
39 KiB
Go

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
}