BUG修复,新的工资计算方式添加遗漏的“考勤及补贴数据”(工作日加班时长、休息日加班时长、带徒天数、满勤奖、请假天数、工龄)
2个文件已修改
115 ■■■■ 已修改文件
service/salary_plan.go 88 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
utils/timex.go 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/salary_plan.go
@@ -9,13 +9,19 @@
    "silkserver/constvar"
    "silkserver/models"
    "silkserver/pkg/logx"
    "silkserver/utils"
    "silkserver/utils/calculator"
    "strconv"
    "strings"
    "time"
)
// WorkingHours 存表:工时计算(日期(年月日)、工种、员工姓名、小组、车台、产量工资、上班超时(小时)、上班超时(天)、加班(单独)、加班(全车间)、出勤(天)、带徒(天)、产量(KG)、其它)
func WorkingHours(date string) error {
    dateTime, err := time.Parse("2006-01-02", date)
    if err != nil {
        return err
    }
    // 人员信息
    workers, err := models.NewWorkerSearch().FindNotTotal()
    if err != nil {
@@ -59,8 +65,13 @@
                }
                workingHours.ShiftClockInTime = attendance.StartWorkTime
                workingHours.ShiftClockOutTime = attendance.EndWorkTime
                workingHours.OvertimeType = constvar.ShiftOvertimeTypeTimeout
                workingHours.OvertimeDuration = attendance.OverTimeDuration
                if dateTime.Weekday() == 0 {
                    workingHours.OvertimeType = constvar.ShiftOvertimeTypeOvertime
                    workingHours.OvertimeDuration = decimal.NewFromInt32(1)
                } else {
                    workingHours.OvertimeType = constvar.ShiftOvertimeTypeTimeout
                    workingHours.OvertimeDuration = attendance.OverTimeDuration
                }
            }
        }
        for _, position := range workerPositions {
@@ -456,7 +467,15 @@
    GroupCarHeadAvgAmount decimal.Decimal // 同组车头工工资
    GroupWeaversAvgAmount decimal.Decimal // 同组挡车工月平均工资
    JobDays               decimal.Decimal // 出勤天数
    WorkingDay            decimal.Decimal // 一个月工作天数
    JobDays               decimal.Decimal // 一个月出勤天数
    ShiftTimeout        decimal.Decimal // 工作日加班时长(小时)
    ShiftOvertime       decimal.Decimal // 休息日加班时长(天)
    MentorDays          decimal.Decimal // 带徒天数
    FullAttendanceAward decimal.Decimal // 满勤奖
    LeaveDays           decimal.Decimal // 请假天数
    Seniority           decimal.Decimal // 工龄
}
// SalaryPlan 生产工资计算
@@ -465,6 +484,10 @@
        return errors.New("请传入正确的查询时间!")
    } else {
        date = date[:7]
    }
    dateTime, err := time.Parse("2006-01", date)
    if err != nil {
        return err
    }
    hours, err := models.NewPayrollWorkingHoursSearch().SetOrder("worker_id").SetMonthly(date).FindNotTotal() // 员工的工时统计
@@ -475,15 +498,28 @@
        return errors.New(date + ":员工打卡信息为空")
    }
    jobQuantityMap := make(map[string]int) // 员工出勤统计
    jobQuantityMap := make(map[string]int)
    shiftTimeoutMap := make(map[string]decimal.Decimal)
    shiftOvertimeMap := make(map[string]decimal.Decimal)
    for _, hour := range hours {
        jobQuantityMap[hour.WorkerID] += 1
        if hour.OvertimeType == constvar.ShiftOvertimeTypeOvertime {
            shiftOvertimeMap[hour.WorkerID] = hour.OvertimeDuration.Add(shiftOvertimeMap[hour.WorkerID])
        } else if hour.OvertimeType == constvar.ShiftOvertimeTypeTimeout {
            shiftTimeoutMap[hour.WorkerID] = hour.OvertimeDuration.Add(shiftTimeoutMap[hour.WorkerID])
        }
    }
    workers, err := models.NewWorkerSearch().FindNotTotal()
    workers, _ := models.NewWorkerSearch().FindNotTotal()
    workerMap := make(map[string]*models.Worker)
    for _, worker := range workers {
        workerMap[worker.ID] = worker
    }
    mentors, _ := models.NewMentorSearch().SetMonth(date).FindNotTotal()
    mentorMap := make(map[string]int)
    for _, mentor := range mentors {
        mentorMap[mentor.WorkerId] = mentor.Days
    }
    // 挡车工工资
@@ -648,24 +684,35 @@
            CreatedBy: "auto",
        }
        monthKey := fmt.Sprintf("%v%v", worker.ShopNumber, worker.GroupNumber)
        fallingSilkBucket := decimal.NewFromInt(0)
        finishTotalAvgAmount := decimal.NewFromInt(0)
        if group, ok := groupByMonthMap[monthKey]; ok {
            fallingSilkBucket = group.FallingSilkBucket
            finishTotalAvgAmount = group.FinishTotalAvgAmount
        }
        firstDay, lastDay := utils.GetLastMonthPeriod(dateTime)
        _, days := utils.CalcWorkHour(firstDay, lastDay, []time.Weekday{time.Sunday}, 12.0)
        parameter := SalaryParameter{
            FallingSilkBucket:     fallingSilkBucket,
            GroupWeaversAvgAmount: finishTotalAvgAmount,
            GroupCarHeadAvgAmount: finishTotalAvgAmount.Div(ready70),
            JobDays:               decimal.NewFromInt32(int32(dayCount)),
            WorkingDay:          decimal.NewFromInt32(int32(days)),
            JobDays:             decimal.NewFromInt32(int32(dayCount)),
            FullAttendanceAward: decimal.NewFromInt32(0), // 满勤奖
            LeaveDays:           decimal.NewFromInt32(0), // 请假天数
            Seniority:           decimal.NewFromInt32(0), // 工龄
        }
        monthKey := fmt.Sprintf("%v%v", worker.ShopNumber, worker.GroupNumber)
        if group, ok := groupByMonthMap[monthKey]; ok {
            parameter.FallingSilkBucket = group.FallingSilkBucket
            parameter.GroupWeaversAvgAmount = group.FinishTotalAvgAmount
            parameter.GroupCarHeadAvgAmount = group.FinishTotalAvgAmount.Div(ready70)
        }
        if timeout, ok := shiftTimeoutMap[hourId]; ok {
            parameter.ShiftTimeout = timeout
        }
        if overtime, ok := shiftOvertimeMap[hourId]; ok {
            parameter.ShiftOvertime = overtime
        }
        if mentorDays, ok := mentorMap[hourId]; ok {
            parameter.MentorDays = decimal.NewFromInt32(int32(mentorDays))
        }
        // 按月算:同组挡车工月平均工资、同组车头工工资、出勤天数
        if workType, ok := salaryPlansMap[worker.WorkTypeId]; ok {
            for _, salaryPlan := range workType.SalaryPlans {
                if matched, _ := regexp.MatchString("(同组挡车工月平均工资)|(同组车头工工资)|(出勤天数)", salaryPlan.SalaryFormula); matched {
                if matched, _ := regexp.MatchString("(同组挡车工月平均工资)|(同组车头工工资)|(出勤天数)|(工作日加班时长)|(休息日加班时长)|(带徒天数)|(满勤奖)|(请假天数)|(工龄)", salaryPlan.SalaryFormula); matched {
                    temp := constitute
                    formula, s := salaryCalculate(&parameter, salaryPlan)
                    temp.SalaryFormula = formula
@@ -710,6 +757,13 @@
    formula = strings.Replace(formula, "同组车头工工资", parameter.GroupCarHeadAvgAmount.String(), -1)
    formula = strings.Replace(formula, "出勤天数", parameter.JobDays.String(), -1)
    formula = strings.Replace(formula, "工作日加班时长", parameter.ShiftTimeout.String(), -1)
    formula = strings.Replace(formula, "休息日加班时长", parameter.ShiftOvertime.String(), -1)
    formula = strings.Replace(formula, "带徒天数", parameter.MentorDays.String(), -1)
    formula = strings.Replace(formula, "满勤奖", parameter.FullAttendanceAward.String(), -1)
    formula = strings.Replace(formula, "请假天数", parameter.LeaveDays.String(), -1)
    formula = strings.Replace(formula, "工龄", parameter.Seniority.String(), -1)
    logx.Debugf("salary formula: %v", formula)
    result, err := calculator.ParseAndExec(formula)
utils/timex.go
@@ -1,6 +1,9 @@
package utils
import "time"
import (
    "slices"
    "time"
)
// IsOverlap 判断两个时间段是否有重叠
func IsOverlap(start1, end1, start2, end2 string) bool {
@@ -22,6 +25,10 @@
    return time.Now().AddDate(0, offset, 0)
}
func GetDayByOffset(offset int) time.Time {
    return time.Now().AddDate(0, 0, offset)
}
// GetLastMonthPeriod 返回上个月的月初时间和月末时间
func GetLastMonthPeriod(now time.Time) (firstDay time.Time, lastDay time.Time) {
    // 获取本个月的第一天的日期(即本月月初)
@@ -40,3 +47,21 @@
func GetMonthDuration(d time.Time) (duration int) {
    return d.AddDate(0, 1, -1).Day()
}
func CalcWorkHour(begin, end time.Time, dayOff []time.Weekday, cellHour float32) (workHour float32, workingCount int) {
    var currentTime = begin
    for {
        if currentTime.After(end) {
            break
        }
        if slices.Contains(dayOff, currentTime.Weekday()) {
            // nothing
        } else {
            workHour += cellHour
            workingCount++
        }
        currentTime = currentTime.AddDate(0, 0, 1) // .Add(24 * time.Hour)
    }
    return float32(workHour), workingCount
}