package service import ( "errors" "fmt" "github.com/shopspring/decimal" "gorm.io/gorm" "regexp" "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 { return err } // 排班信息(功能缺失) // 打卡信息(通过人员关联) 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 { workingHours := models.PayrollWorkingHours{ Cycle: date, WorkTypeID: worker.WorkTypeId, WorkTypeCode: worker.WorkTypeCode, WorkerID: worker.ID, } for _, attendance := range attendances { if worker.ID == attendance.WorkerId { workingHours.ShiftTime = fmt.Sprintf("%v-%v", attendance.ClassesStartTime, attendance.ClassesEndTime) if attendance.ClassesStartTime != "" && attendance.ClassesEndTime != "" { startH, _ := strconv.Atoi(strings.Split(attendance.ClassesStartTime, ":")[0]) endH, _ := strconv.Atoi(strings.Split(attendance.ClassesEndTime, ":")[0]) if startH > endH { workingHours.ShiftCrossDay = true } } workingHours.ShiftClockInTime = attendance.StartWorkTime workingHours.ShiftClockOutTime = attendance.EndWorkTime 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 { if worker.ID == position.WorkerId { //workingHours.WorkshopId = position.Workshop workingHours.WorkshopNumber = position.Workshop workingHours.GroupNumber = position.WorkshopGroup //workingHours.CarNumbers = fmt.Sprintf("%v-%v", position.StartWorkerPosition, position.EndWorkerPosition) workingHours.StartCarNumber = position.StartWorkerPosition workingHours.EndCarNumber = position.EndWorkerPosition continue } } list = append(list, &workingHours) } 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 } if err := models.NewPayrollWorkingHoursSearch().SetOrm(db).CreateBatch(list); err != nil { return err } return nil }) return nil } // ProductionCar 存表:车台每日产量统计 (日期(年月日)、车间、车台、庄口、期望等级、成品等级、丝量、丝单价(json)、野纤、野纤单价(json)、丝量金额、野纤金额、成品金额(丝量金额-野纤金额)) func ProductionCar(date string) error { yieldRegisters, err := models.NewYieldRegisterSearch().SetCreateTime(date).FindNotTotal() // 产量登记 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 } finenessChecks, err := models.NewFinenessCheckSearch().SetFinenessRegisterIDs(finenessIds).FindAll() // 纤度检验 if err != nil { return err } 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 } workingHours, err := models.NewPayrollWorkingHoursSearch().SetWorkTypeCode(constvar.JobTypeWeavers).SetCycle(date).FindNotTotal() // 员工的工时统计 if err != nil { return err } if len(workingHours) == 0 { return errors.New(date + ":挡车工打卡信息为空") } // 车台挡车工重复人员标记 carEmployeeMap := make(map[string]map[string]bool) // map[车间\组别\车号]map[人员ID]true // 方案1 根据打卡员工来查人数 workingHourArr := make([]models.PayrollWorkingHours, 0) for _, workingHour := range workingHours { for i := workingHour.StartCarNumber; i <= workingHour.EndCarNumber; i++ { workingHourArr = append(workingHourArr, models.PayrollWorkingHours{ Cycle: workingHour.Cycle, WorkTypeID: workingHour.WorkTypeID, WorkTypeCode: workingHour.WorkTypeCode, WorkerID: workingHour.WorkerID, WorkshopId: workingHour.WorkshopId, WorkshopNumber: workingHour.WorkshopNumber, GroupNumber: workingHour.GroupNumber, StartCarNumber: i, }) } } for _, workingHour := range workingHourArr { key := fmt.Sprintf("%v%v%v", workingHour.WorkshopNumber, workingHour.GroupNumber, workingHour.StartCarNumber) if temp, ok := carEmployeeMap[key]; ok { temp[workingHour.WorkerID] = true carEmployeeMap[key] = temp } else { carEmployeeMap[key] = map[string]bool{workingHour.WorkerID: true} } } // 方案2 根据纤度登记来查人数 /* for _, yield := range yieldRegisters { for _, workingHour := range workingHours { if yield.WorkshopNumber == workingHour.WorkshopNumber && yield.GroupNumber == workingHour.GroupNumber { for _, circle := range yield.Circles { if circle.CarNumber >= workingHour.StartCarNumber && circle.CarNumber <= workingHour.EndCarNumber { key := fmt.Sprintf("%v%v%v", workingHour.WorkshopNumber, workingHour.GroupNumber, circle.CarNumber) carEmployeeMap[key][workingHour.WorkerID] = true } } } } }*/ productionCar := make([]*models.PayrollProductionCar, 0) for _, yield := range yieldRegisters { info := models.PayrollProductionCar{ Cycle: date, WorkshopId: yield.WorkshopId, WorkshopNumber: yield.WorkshopNumber, GroupNumber: yield.GroupNumber, MarketId: yield.MarketId, MarketNumber: yield.MarketNumber, MarketName: yield.MarketName, FallingSilkBucket: yield.FallingSilkBucketOne.Add(yield.FallingSilkBucketTwo).Add(yield.FallingSilkBucketThree), Spec: yield.Spec, CarWorkQuantity: 1, } for _, check := range finenessChecks { // 庄口、车间、组别 if yield.MarketId == check.FinenessRegister.MarketId && yield.WorkshopNumber == check.FinenessRegister.WorkshopNumber && yield.GroupNumber == check.FinenessRegister.WorkshopGroup { info.FinishLevel = check.FinenessGrade key := fmt.Sprintf("%v%v", info.MarketNumber, info.FinishLevel) if payStandard, ok := priceStandardMap[key]; ok { info.SilkUnitAmount = payStandard } continue } } silkQuantityMap := make(map[int]decimal.Decimal) // map[车号]数量 丝量 for _, circle := range yield.Circles { if yield.ID == circle.YieldRegisterId { silkQuantityMap[circle.CarNumber] = silkQuantityMap[circle.CarNumber].Add(circle.Value) } } // 野纤统计 badSilkQuantityMap := make(map[int]map[string]int) // map[车号]map[纤度等级]数量 for _, check := range finenessChecks { if yield.MarketId == check.FinenessRegister.MarketId && yield.WorkshopNumber == check.FinenessRegister.WorkshopNumber && yield.GroupNumber == check.FinenessRegister.WorkshopGroup { if strings.Contains(check.FinenessGrade, "野") { badSilkQuantityMap[check.FinenessRegister.Position][check.FinenessGrade] += 1 } } } for carNumber := range silkQuantityMap { result := info result.CarNumber = carNumber // 一车多人,算平均 key := fmt.Sprintf("%v%v%v", yield.WorkshopNumber, yield.GroupNumber, carNumber) if workIdMap, ok := carEmployeeMap[key]; ok { result.CarWorkQuantity = len(workIdMap) for workId := range workIdMap { result.CarWorkIds += fmt.Sprintf("%v,", workId) } } // 野纤 if badSilk, ok := badSilkQuantityMap[carNumber]; ok { quantityTmp := 0 totalAmount := decimal.NewFromInt32(0) for finenessGrade := range badSilk { quantityTmp += badSilk[finenessGrade] for _, price := range priceStandards { if price.MarketId == result.MarketId && price.RawSilkGrade == finenessGrade { result.BadSilkUnitAmount = price.PayStandard totalAmount = totalAmount.Add(result.BadSilkUnitAmount.Mul(decimal.NewFromInt32(int32(badSilk[finenessGrade])))) continue } } result.BadSilkType += fmt.Sprintf("%v,", finenessGrade) } result.BadSilkQuantity = decimal.NewFromInt32(int32(quantityTmp)) result.BadSilkAvgQuantity = result.BadSilkQuantity.Div(decimal.NewFromInt32(int32(result.CarWorkQuantity))) result.BadSilkTotalAmount = totalAmount result.BadSilkTotalAvgAmount = totalAmount.Div(decimal.NewFromInt32(int32(result.CarWorkQuantity))) } result.SilkQuantity = silkQuantityMap[carNumber] result.SilkAvgQuantity = result.SilkQuantity.Div(decimal.NewFromInt32(int32(result.CarWorkQuantity))) result.SilkTotalAmount = result.SilkQuantity.Mul(result.SilkUnitAmount) result.SilkTotalAvgAmount = result.SilkQuantity.Mul(result.SilkUnitAmount).Div(decimal.NewFromInt32(int32(result.CarWorkQuantity))) result.FinishTotalAmount = result.SilkTotalAmount.Sub(result.BadSilkTotalAmount) productionCar = append(productionCar, &result) } } 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 } if err = models.NewPayrollProductionCarSearch().SetOrm(db).CreateBatch(productionCar); err != nil { return err } return nil }) if err != nil { return err } return nil } // ProductionGroup 存表:小组每天的产量登记 func ProductionGroup(date string) error { productionCars, err := models.NewPayrollProductionCarSearch().SetOrder("workshop_number, group_number"). SetCycle(date).FindNotTotal() // 车台每天的产量统计 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) 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) for i := 0; i < len(productionCars); i++ { group := models.PayrollProductionGroup{ Cycle: date, WorkshopId: productionCars[i].WorkshopId, WorkshopNumber: productionCars[i].WorkshopNumber, GroupNumber: productionCars[i].GroupNumber, } for j := i; j < len(productionCars); j++ { if productionCars[i].WorkshopNumber == productionCars[j].WorkshopNumber && productionCars[i].GroupNumber == productionGroupList[j].GroupNumber { counter := 1 key := fmt.Sprintf("%v%v", productionGroupList[j].WorkshopNumber, productionGroupList[j].GroupNumber) if le := len(groupWorkingHourMap[key]); le > 0 { counter = le } // 一车多人,算平均 counterD := decimal.NewFromInt32(int32(counter)) group.SilkQuantity = group.SilkQuantity.Add(productionCars[j].SilkQuantity) group.SilkAvgQuantity = group.SilkAvgQuantity.Add(productionCars[j].SilkAvgQuantity).Div(counterD) group.SilkTotalAmount = group.SilkTotalAmount.Add(productionCars[j].SilkTotalAmount) group.SilkTotalAvgAmount = group.SilkTotalAvgAmount.Add(productionCars[j].SilkTotalAvgAmount).Div(counterD) group.BadSilkQuantity = group.BadSilkQuantity.Add(productionCars[j].BadSilkQuantity) group.BadSilkTotalAmount = group.BadSilkTotalAmount.Add(productionCars[j].BadSilkTotalAmount) group.BadSilkTotalAvgAmount = group.BadSilkTotalAvgAmount.Add(productionCars[j].BadSilkTotalAvgAmount).Div(counterD) group.FinishTotalAmount = group.FinishTotalAmount.Add(productionCars[j].FinishTotalAmount) group.FinishTotalAvgAmount = group.FinishTotalAvgAmount.Add(productionCars[j].FinishTotalAvgAmount).Div(counterD) group.FallingSilkBucket = group.FallingSilkBucket.Add(productionCars[j].FallingSilkBucket) // 跳过重复项 if i != j { i += 1 } } } productionGroupList = append(productionGroupList, &group) } err = models.WithTransaction(func(db *gorm.DB) error { if len(productionGroupList) == 0 { return nil } if err := models.NewPayrollProductionGroupSearch().SetOrm(db).SetCycle(date).Delete(); err != nil { return err } if err = models.NewPayrollProductionGroupSearch().SetOrm(db).CreateBatch(productionGroupList); err != nil { return err } return nil }) if err != nil { return err } return nil } // ProductionWeavers 存表: 挡车工每人每天的产量统计登记 func ProductionWeavers(date string) error { workingHours, err := models.NewPayrollWorkingHoursSearch().SetWorkTypeCode(constvar.JobTypeWeavers).SetCycle(date).FindNotTotal() // 员工的工时统计 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) for _, worker := range workingHours { info := models.PayrollProductionWeavers{ Cycle: date, WorkTypeID: worker.WorkTypeID, WorkerID: worker.WorkerID, WorkshopId: worker.WorkshopId, WorkshopNumber: worker.WorkshopNumber, GroupNumber: worker.GroupNumber, } for _, car := range productionCars { if car.WorkshopNumber == worker.WorkshopNumber && car.GroupNumber == worker.GroupNumber && car.CarNumber >= worker.StartCarNumber && car.CarNumber <= worker.EndCarNumber { info.CarNumbers += fmt.Sprintf("%d,", car.CarNumber) info.SilkQuantity = info.SilkQuantity.Add(car.SilkAvgQuantity) info.SilkTotalAmount = info.SilkTotalAmount.Add(car.SilkTotalAvgAmount) info.BadSilkQuantity = info.BadSilkQuantity.Add(car.BadSilkAvgQuantity) info.BadSilkTotalAmount = info.BadSilkTotalAmount.Add(car.BadSilkTotalAvgAmount) 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 } if err = models.NewPayrollProductionWeaversSearch().SetOrm(db).CreateBatch(productionEmployee); err != nil { return err } return nil }) return nil } type SalaryParameter struct { SilkQuantity decimal.Decimal // 日产丝量 SilkUnitAmount decimal.Decimal // 生丝单价 SilkTotalAmount decimal.Decimal // 生丝总价(=日产丝量*生丝单价) FallingSilkBucket decimal.Decimal // 桶数 BadSilkQuantity decimal.Decimal // 野纤数量 BadSilkUnitAmount decimal.Decimal // 野纤单价 BadSilkTotalAmount decimal.Decimal // 野纤总价 GroupCarHeadAvgAmount decimal.Decimal // 同组车头工工资 GroupWeaversAvgAmount 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 生产工资计算 func SalaryPlan(date string) error { if len(date) < 7 { 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() // 员工的工时统计 if err != nil { return err } if len(hours) == 0 { return errors.New(date + ":员工打卡信息为空") } 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, _ := 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 } // 挡车工工资 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) weaversAmountMap[key] = weaver } // 工种工资方案 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 { key := fmt.Sprintf("%v%v%v", group.Cycle, group.WorkshopNumber, group.GroupNumber) groupMap[key] = group monthKey := fmt.Sprintf("%v%v", group.WorkshopNumber, group.GroupNumber) if groupByM, ok := groupByMonthMap[monthKey]; ok { groupByM.FallingSilkBucket = groupByM.FallingSilkBucket.Add(group.FallingSilkBucket) groupByM.SilkQuantity = groupByM.SilkQuantity.Add(group.SilkQuantity) groupByM.SilkAvgQuantity = groupByM.SilkAvgQuantity.Add(group.SilkAvgQuantity) groupByM.SilkTotalAmount = groupByM.SilkTotalAmount.Add(group.SilkTotalAmount) groupByM.SilkTotalAvgAmount = groupByM.SilkTotalAvgAmount.Add(group.SilkTotalAvgAmount) groupByM.BadSilkQuantity = groupByM.BadSilkQuantity.Add(group.BadSilkQuantity) groupByM.BadSilkTotalAmount = groupByM.BadSilkTotalAmount.Add(group.BadSilkTotalAmount) groupByM.BadSilkTotalAvgAmount = groupByM.BadSilkTotalAvgAmount.Add(group.BadSilkTotalAvgAmount) groupByM.FinishTotalAmount = groupByM.FinishTotalAmount.Add(group.FinishTotalAmount) groupByM.FinishTotalAvgAmount = groupByM.FinishTotalAvgAmount.Add(group.FinishTotalAvgAmount) groupByMonthMap[monthKey] = groupByM } else { groupByMonthMap[monthKey] = group } } var productionByDay []*models.PayrollOtherSubsidies // 按天统计,每天的工资 for _, hour := range hours { production := models.PayrollOtherSubsidies{ Cycle: hour.Cycle, WorkerID: hour.WorkerID, WorkTypeID: hour.WorkTypeID, WorkTypeCode: hour.WorkTypeCode, WorkTypeName: constvar.JobTypeMap[hour.WorkTypeCode], //SalaryPlanIds: "", //Amount: decimal.NewFromInt32(0), } // 按天算:日产丝量、生丝单价、桶数、野纤数量、野纤单价 groupKey := fmt.Sprintf("%v%v%v", hour.Cycle, hour.WorkshopNumber, hour.GroupNumber) 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 } 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(¶meter, 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 } if err = models.NewPayrollOtherSubsidiesSearch().SetOrm(db).CreateBatch(productionByDay); err != nil { return err } return nil }) var constituteByMonth []*models.PayrollConstitute // 按天算的合并 productionByMonthMap := make(map[string]*models.PayrollOtherSubsidies) for _, production := range productionByDay { key := fmt.Sprintf("%%", production.WorkerID, production.SalaryPlanId) // 用户id/方案ID if groupByM, ok := productionByMonthMap[key]; ok { productionByMonthMap[key].Amount = groupByM.Amount.Add(production.Amount) } else { productionByMonthMap[key] = production } } for _, production := range productionByMonthMap { constituteByMonth = append(constituteByMonth, &models.PayrollConstitute{ Cycle: date, WorkerID: production.WorkerID, WorkTypeID: production.WorkTypeID, WorkTypeCode: production.WorkTypeCode, SalaryPlanId: production.SalaryPlanId, SalaryFormula: "", Amount: production.Amount, CreatedBy: "auto", }) // 每个人的所有方案 } // 按月算的计算 for hourId, dayCount := range jobQuantityMap { worker := workerMap[hourId] // 员工信息 ready70 := decimal.NewFromInt32(6) // 70绪 //ready100 := decimal.NewFromInt32(4) // 100绪 //coefficient := decimal.NewFromInt32(1) // 系数 constitute := models.PayrollConstitute{ Cycle: date, WorkerID: hourId, WorkTypeID: worker.WorkTypeId, WorkTypeCode: worker.WorkTypeCode, //SalaryPlanId:, //SalaryFormula:, //Amount:, CreatedBy: "auto", } firstDay, lastDay := utils.GetLastMonthPeriod(dateTime) _, days := utils.CalcWorkHour(firstDay, lastDay, []time.Weekday{time.Sunday}, 12.0) parameter := SalaryParameter{ 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 { temp := constitute formula, s := salaryCalculate(¶meter, salaryPlan) temp.SalaryFormula = formula temp.SalaryPlanId = salaryPlan.ID temp.Amount = temp.Amount.Add(s) constituteByMonth = append(constituteByMonth, &temp) // 每个人的所有方案 } } } } 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 } if err = models.NewPayrollConstituteSearch().SetOrm(db).CreateBatch(constituteByMonth); err != nil { return err } return nil }) return nil } // 根据方案计算各工种薪资 func salaryCalculate(parameter *SalaryParameter, salaryPlan *models.SalaryPlan) (string, decimal.Decimal) { formula := strings.ReplaceAll(salaryPlan.SalaryFormula, ",", "") formula = strings.ReplaceAll(salaryPlan.SalaryFormula, " ", "") //var SplitFixedField = []string{"日产丝量", "生丝单价", "桶数", "野纤数量", "野纤单价", "同组挡车工月平均工资", "同组车头工工资", "出勤天数"} formula = strings.Replace(formula, "日产丝量*生丝单价", parameter.SilkTotalAmount.String(), -1) formula = strings.Replace(formula, "野纤数量*野纤单价", parameter.BadSilkTotalAmount.String(), -1) formula = strings.Replace(formula, "日产丝量", parameter.SilkQuantity.String(), -1) formula = strings.Replace(formula, "生丝单价", parameter.SilkTotalAmount.String(), -1) formula = strings.Replace(formula, "桶数", parameter.FallingSilkBucket.String(), -1) formula = strings.Replace(formula, "野纤数量", parameter.BadSilkQuantity.String(), -1) formula = strings.Replace(formula, "野纤单价", parameter.BadSilkUnitAmount.String(), -1) formula = strings.Replace(formula, "同组挡车工月平均工资", parameter.GroupWeaversAvgAmount.String(), -1) 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) if err != nil { logx.Errorf("%s : %v", formula, err) } logx.Debugf("%s = %v", formula, result) return formula, decimal.NewFromFloat(result) }