yinbentan
2024-08-01 edf3066724ad442d6929210c830cb67c17277690
添加工资计算自动任务
1个文件已添加
3个文件已修改
279 ■■■■ 已修改文件
models/payroll_working_hours.go 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/salary_plan.go 170 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
task/salary_plan.go 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
task/task_init.go 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/payroll_working_hours.go
@@ -133,6 +133,10 @@
        db = db.Where("work_type_id = ?", slf.WorkTypeID)
    }
    if slf.WorkTypeCode != "" {
        db = db.Where("work_type_code = ?", slf.WorkTypeCode)
    }
    if slf.WorkerID != "" {
        db = db.Where("worker_id = ?", slf.WorkerID)
    }
service/salary_plan.go
@@ -25,9 +25,18 @@
    // 排班信息(功能缺失)
    // 打卡信息(通过人员关联)
    attendances, err := models.NewAttendanceManageSearch().SetDate(date).FindNotTotal()
    if err != nil {
        return err
    }
    if len(attendances) == 0 {
        return errors.New(date + ":打卡信息为空")
    }
    // 车台信息(通过人员关联)
    workerPositions, err := models.NewWorkerPositionSearch().SetOverlappingDate(date, date).FindAll()
    if err != nil {
        return err
    }
    list := make([]*models.PayrollWorkingHours, 0)
    for _, worker := range workers {
@@ -70,6 +79,9 @@
    }
    err = models.WithTransaction(func(db *gorm.DB) error {
        if len(list) == 0 {
            return nil
        }
        if err := models.NewPayrollWorkingHoursSearch().SetOrm(db).SetCycle(date).Delete(); err != nil {
            return err
        }
@@ -88,10 +100,18 @@
    if err != nil {
        return err
    }
    if len(yieldRegisters) == 0 {
        return errors.New(date + ":产量登记为空")
    }
    finenesss, err := models.NewFinenessRegisterSearch().SetFinishDate(date).FindAll() // 纤度登记
    if err != nil {
        return err
    }
    if len(finenesss) == 0 {
        return errors.New(date + ":纤度登记为空")
    }
    finenessIds := make([]uint, len(finenesss))
    for i, fineness := range finenesss {
        finenessIds[i] = fineness.ID
@@ -101,8 +121,15 @@
        return err
    }
    priceStandards, _ := models.NewRawSilkPriceStandardSearch().FindNotTotal() // 生丝定价
    priceStandardMap := make(map[string]decimal.Decimal)                       // map[庄口\标号]定价
    priceStandards, err := models.NewRawSilkPriceStandardSearch().FindNotTotal() // 生丝定价
    if err != nil {
        return err
    }
    if len(priceStandards) == 0 {
        return errors.New(date + ":生丝定价为空")
    }
    priceStandardMap := make(map[string]decimal.Decimal) // map[庄口\标号]定价
    for _, price := range priceStandards {
        key := fmt.Sprintf("%d%s", price.MarketNumber, price.RawSilkGrade)
        priceStandardMap[key] = price.PayStandard
@@ -111,6 +138,9 @@
    workingHours, err := models.NewPayrollWorkingHoursSearch().SetWorkTypeCode(constvar.JobTypeWeavers).SetCycle(date).FindNotTotal() // 员工的工时统计
    if err != nil {
        return err
    }
    if len(workingHours) == 0 {
        return errors.New(date + ":挡车工打卡信息为空")
    }
    // 车台挡车工重复人员标记
@@ -133,7 +163,13 @@
    }
    for _, workingHour := range workingHourArr {
        key := fmt.Sprintf("%v%v%v", workingHour.WorkshopNumber, workingHour.GroupNumber, workingHour.StartCarNumber)
        carEmployeeMap[key][workingHour.WorkerID] = true
        if temp, ok := carEmployeeMap[key]; ok {
            temp[workingHour.WorkerID] = true
            carEmployeeMap[key] = temp
        } else {
            carEmployeeMap[key] = map[string]bool{workingHour.WorkerID: true}
        }
    }
    // 方案2 根据纤度登记来查人数
@@ -241,6 +277,9 @@
    }
    err = models.WithTransaction(func(db *gorm.DB) error {
        if len(productionCar) == 0 {
            return nil
        }
        if err := models.NewPayrollProductionCarSearch().SetOrm(db).SetCycle(date).Delete(); err != nil {
            return err
        }
@@ -263,16 +302,27 @@
    if err != nil {
        return err
    }
    if len(productionCars) == 0 {
        errors.New(date + ":车台每天的产量统计为空")
    }
    workingHours, err := models.NewPayrollWorkingHoursSearch().SetWorkTypeCode(constvar.JobTypeWeavers).SetCycle(date).FindNotTotal() // 员工的工时统计
    if err != nil {
        return err
    }
    if len(workingHours) == 0 {
        return errors.New(date + ":挡车工打卡信息为空")
    }
    groupWorkingHourMap := make(map[string]map[string]bool)
    for _, workingHour := range workingHours {
        key := fmt.Sprintf("%v%v", workingHour.WorkshopNumber, workingHour.GroupNumber)
        groupWorkingHourMap[key][workingHour.WorkerID] = true
        if temp, ok := groupWorkingHourMap[key]; ok {
            temp[workingHour.WorkerID] = true
            groupWorkingHourMap[key] = temp
        } else {
            groupWorkingHourMap[key] = map[string]bool{workingHour.WorkerID: true}
        }
    }
    productionGroupList := make([]*models.PayrollProductionGroup, 0)
@@ -316,12 +366,13 @@
    }
    err = models.WithTransaction(func(db *gorm.DB) error {
        err := models.NewPayrollProductionGroupSearch().SetOrm(db).SetCycle(date).Delete()
        if err != nil {
        if len(productionGroupList) == 0 {
            return nil
        }
        if err := models.NewPayrollProductionGroupSearch().SetOrm(db).SetCycle(date).Delete(); err != nil {
            return err
        }
        err = models.NewPayrollProductionGroupSearch().SetOrm(db).CreateBatch(productionGroupList)
        if err != nil {
        if err = models.NewPayrollProductionGroupSearch().SetOrm(db).CreateBatch(productionGroupList); err != nil {
            return err
        }
        return nil
@@ -339,10 +390,16 @@
    if err != nil {
        return err
    }
    if len(workingHours) == 0 {
        return errors.New(date + ":挡车工打卡信息为空")
    }
    productionCars, err := models.NewPayrollProductionCarSearch().SetCycle(date).FindNotTotal()
    if err != nil {
        return err
    }
    if len(productionCars) == 0 {
        return errors.New(date + ":车台每天产量统计为空")
    }
    productionEmployee := make([]*models.PayrollProductionWeavers, 0)
@@ -366,10 +423,16 @@
                info.FinishTotalAmount = info.FinishTotalAmount.Add(car.FinishTotalAvgAmount)
            }
        }
        if info.SilkQuantity.IsZero() {
            continue
        }
        productionEmployee = append(productionEmployee, &info)
    }
    err = models.WithTransaction(func(db *gorm.DB) error {
        if len(productionEmployee) == 0 {
            return nil
        }
        if err := models.NewPayrollProductionWeaversSearch().SetOrm(db).SetCycle(date).Delete(); err != nil {
            return err
        }
@@ -408,6 +471,10 @@
    if err != nil {
        return err
    }
    if len(hours) == 0 {
        return errors.New(date + ":员工打卡信息为空")
    }
    jobQuantityMap := make(map[string]int) // 员工出勤统计
    for _, hour := range hours {
        jobQuantityMap[hour.WorkerID] += 1
@@ -420,7 +487,11 @@
    }
    // 挡车工工资
    weaversAmountArr, _ := models.NewPayrollProductionWeaversSearch().SetMonthly(date).FindNotTotal()
    weaversAmountArr, err := models.NewPayrollProductionWeaversSearch().SetMonthly(date).FindNotTotal()
    if err != nil {
        return err
    }
    weaversAmountMap := make(map[string]*models.PayrollProductionWeavers, len(weaversAmountArr))
    for _, weaver := range weaversAmountArr {
        key := fmt.Sprintf("%v%v", weaver.Cycle, weaver.WorkerID)
@@ -429,12 +500,23 @@
    // 工种工资方案 map[工种]方案
    salaryPlans, _ := models.NewWorkTypeManageSearch().FindNotTotal()
    if len(salaryPlans) == 0 {
        return errors.New(date + ":工资方案为空")
    }
    salaryPlansMap := make(map[uint]*models.WorkTypeManage, len(salaryPlans))
    for _, salaryPlan := range salaryPlans {
        salaryPlansMap[salaryPlan.ID] = salaryPlan
    }
    groups, err := models.NewPayrollProductionGroupSearch().SetMonthly(date).FindNotTotal()
    if err != nil {
        return err
    }
    if len(groups) == 0 {
        return errors.New(date + ":小组每天的产量为空")
    }
    groupMap := make(map[string]*models.PayrollProductionGroup, len(groups))
    groupByMonthMap := make(map[string]*models.PayrollProductionGroup, len(groups))
    for _, group := range groups {
@@ -475,36 +557,46 @@
        // 按天算:日产丝量、生丝单价、桶数、野纤数量、野纤单价
        groupKey := fmt.Sprintf("%v%v%v", hour.Cycle, hour.WorkshopNumber, hour.GroupNumber)
        group := groupMap[groupKey]
        weaversKey := fmt.Sprintf("%v%v", hour.Cycle, hour.WorkerID)
        weavers := weaversAmountMap[weaversKey]
        parameter := SalaryParameter{
            SilkQuantity:       group.SilkQuantity,
            SilkUnitAmount:     decimal.NewFromInt32(1),
            SilkTotalAmount:    weavers.FinishTotalAmount,
            FallingSilkBucket:  group.FallingSilkBucket,
            BadSilkQuantity:    group.BadSilkQuantity,
            BadSilkUnitAmount:  decimal.NewFromInt32(1),
            BadSilkTotalAmount: weavers.BadSilkTotalAmount,
        }
        if workType, ok := salaryPlansMap[hour.WorkTypeID]; ok {
            for _, salaryPlan := range workType.SalaryPlans {
                if matched, _ := regexp.MatchString("(日产丝量)|(生丝单价)|(桶数)|(野纤数量)|(野纤单价)", salaryPlan.SalaryFormula); matched {
                    temp := production
                    formula, s := salaryCalculate(&parameter, salaryPlan)
        if group, ok := groupMap[groupKey]; ok {
            weaversKey := fmt.Sprintf("%v%v", hour.Cycle, hour.WorkerID)
            finishTotalAmount := decimal.NewFromInt32(0)
            badSilkTotalAmount := decimal.NewFromInt32(0)
            if weavers, ok := weaversAmountMap[weaversKey]; ok {
                finishTotalAmount = weavers.FinishTotalAmount
                badSilkTotalAmount = weavers.BadSilkTotalAmount
            }
                    temp.SalaryFormula = formula
                    temp.SalaryPlanId = salaryPlan.ID
                    temp.Amount = temp.Amount.Add(s)
                    productionByDay = append(productionByDay, &temp) // 每个人的所有方案
            parameter := SalaryParameter{
                SilkQuantity:       group.SilkQuantity,
                SilkUnitAmount:     decimal.NewFromInt32(1),
                SilkTotalAmount:    finishTotalAmount,
                FallingSilkBucket:  group.FallingSilkBucket,
                BadSilkQuantity:    group.BadSilkQuantity,
                BadSilkUnitAmount:  decimal.NewFromInt32(1),
                BadSilkTotalAmount: badSilkTotalAmount,
            }
            if workType, ok := salaryPlansMap[hour.WorkTypeID]; ok {
                for _, salaryPlan := range workType.SalaryPlans {
                    if matched, _ := regexp.MatchString("(日产丝量)|(生丝单价)|(桶数)|(野纤数量)|(野纤单价)", salaryPlan.SalaryFormula); matched {
                        temp := production
                        formula, s := salaryCalculate(&parameter, salaryPlan)
                        temp.SalaryFormula = formula
                        temp.SalaryPlanId = salaryPlan.ID
                        temp.Amount = temp.Amount.Add(s)
                        productionByDay = append(productionByDay, &temp) // 每个人的所有方案
                    }
                }
            }
        }
    }
    err = models.WithTransaction(func(db *gorm.DB) error {
        if len(productionByDay) == 0 {
            return nil
        }
        if err := models.NewPayrollOtherSubsidiesSearch().SetOrm(db).SetMonthly(date).Delete(); err != nil {
            return err
        }
@@ -557,11 +649,16 @@
        }
        monthKey := fmt.Sprintf("%v%v", worker.ShopNumber, worker.GroupNumber)
        group := groupByMonthMap[monthKey]
        fallingSilkBucket := decimal.NewFromInt(0)
        finishTotalAvgAmount := decimal.NewFromInt(0)
        if group, ok := groupByMonthMap[monthKey]; ok {
            fallingSilkBucket = group.FallingSilkBucket
            finishTotalAvgAmount = group.FinishTotalAvgAmount
        }
        parameter := SalaryParameter{
            FallingSilkBucket:     group.FallingSilkBucket,
            GroupWeaversAvgAmount: group.FinishTotalAvgAmount,
            GroupCarHeadAvgAmount: group.FinishTotalAvgAmount.Div(ready70),
            FallingSilkBucket:     fallingSilkBucket,
            GroupWeaversAvgAmount: finishTotalAvgAmount,
            GroupCarHeadAvgAmount: finishTotalAvgAmount.Div(ready70),
            JobDays:               decimal.NewFromInt32(int32(dayCount)),
        }
@@ -582,6 +679,9 @@
    }
    err = models.WithTransaction(func(db *gorm.DB) error {
        if len(constituteByMonth) == 0 {
            return nil
        }
        if err := models.NewPayrollConstituteSearch().SetOrm(db).SetCycle(date).SetCreatedBy("auto").Delete(); err != nil {
            return err
        }
task/salary_plan.go
New file
@@ -0,0 +1,101 @@
package task
import (
    "silkserver/models"
    "silkserver/pkg/logx"
    "silkserver/service"
    "silkserver/utils"
)
func WorkingHours() {
    //加锁,只需要一个进程运行此任务
    var (
        lockName  = "WorkingHours"
        serviceID = "WorkingHoursServer"
    )
    err := models.NewLockSearch().AcquireLock(lockName, serviceID)
    if err != nil {
        logx.Errorf("MonthStats AcquireLock err:%v", err)
        return
    }
    defer func() {
        err := models.NewLockSearch().ReleaseLock(lockName, serviceID)
        if err != nil {
            logx.Errorf("MonthStats ReleaseLock err:%v", err)
        }
    }()
    firstDay, lastDay := utils.GetLastMonthPeriod(utils.GetMonthByOffset(-1))
    for i := firstDay.Day() - 1; i <= lastDay.Day(); i++ {
        localDay := firstDay.AddDate(0, 0, i-1).Format("2006-01-02")
        err = service.WorkingHours(localDay)
        if err != nil {
            logx.Error(err.Error())
        }
    }
}
func ProductionCar() {
    //加锁,只需要一个进程运行此任务
    var (
        lockName  = "ProductionCar"
        serviceID = "ProductionCarServer"
    )
    err := models.NewLockSearch().AcquireLock(lockName, serviceID)
    if err != nil {
        logx.Errorf("MonthStats AcquireLock err:%v", err)
        return
    }
    defer func() {
        err := models.NewLockSearch().ReleaseLock(lockName, serviceID)
        if err != nil {
            logx.Errorf("MonthStats ReleaseLock err:%v", err)
        }
    }()
    firstDay, lastDay := utils.GetLastMonthPeriod(utils.GetMonthByOffset(-1))
    for i := 0; i < lastDay.Day(); i++ {
        localDay := firstDay.AddDate(0, 0, i).Format("2006-01-02")
        err = service.ProductionCar(localDay)
        if err != nil {
            logx.Error(err.Error())
        }
        err = service.ProductionGroup(localDay)
        if err != nil {
            logx.Error(err.Error())
        }
        err = service.ProductionWeavers(localDay)
        if err != nil {
            logx.Error(err.Error())
        }
    }
}
func SalaryPlan() {
    //加锁,只需要一个进程运行此任务
    var (
        lockName  = "SalaryPlan"
        serviceID = "SalaryPlanServer"
    )
    err := models.NewLockSearch().AcquireLock(lockName, serviceID)
    if err != nil {
        logx.Errorf("MonthStats AcquireLock err:%v", err)
        return
    }
    defer func() {
        err := models.NewLockSearch().ReleaseLock(lockName, serviceID)
        if err != nil {
            logx.Errorf("MonthStats ReleaseLock err:%v", err)
        }
    }()
    lastMonth := utils.GetMonthByOffset(-1).Format("2006-01")
    err = service.SalaryPlan(lastMonth)
    if err != nil {
        logx.Error(err.Error())
    }
}
task/task_init.go
@@ -17,5 +17,9 @@
        logx.Errorf("init task err:%v", err)
        panic(err)
    }
    s.Every(1).Month(1).Do(WorkingHours)
    s.Every(1).Month(1).Do(ProductionCar)
    s.Every(1).Month(1).Do(SalaryPlan)
    s.StartAsync()
}