yinbentan
2024-07-31 b94bef381946e22fd1038f24e6d9de911d194640
service/salary_plan.go
@@ -5,21 +5,14 @@
   "fmt"
   "github.com/shopspring/decimal"
   "gorm.io/gorm"
   "regexp"
   "silkserver/constvar"
   "silkserver/models"
   "silkserver/pkg/logx"
   "silkserver/utils/calculator"
   "strconv"
   "strings"
)
type WeaversAmount struct {
   WorkerID string          `json:"workerID"`
   Amount   decimal.Decimal `json:"amount"`
}
// 薪资计算
// 纤度登记:silk_fineness_register   silk_fineness_register_item
// 纤度检验:silk_fineness_check   silk_fineness_check_item
// 产量登记登记:silk_yield_register_circle
// WorkingHours 存表:工时计算(日期(年月日)、工种、员工姓名、小组、车台、产量工资、上班超时(小时)、上班超时(天)、加班(单独)、加班(全车间)、出勤(天)、带徒(天)、产量(KG)、其它)
func WorkingHours(date string) error {
@@ -77,10 +70,12 @@
   }
   err = models.WithTransaction(func(db *gorm.DB) error {
      models.NewPayrollWorkingHoursSearch().SetOrm(db).SetCycle(date).Delete()
      models.NewPayrollWorkingHoursSearch().SetOrm(db).CreateBatch(list)
      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
   })
@@ -119,26 +114,47 @@
   }
   // 车台挡车工重复人员标记
   carEmployeeMap := make(map[string]map[string]bool) // map[车间\组别\车号]map[人员]true
   for _, yield := range yieldRegisters {
   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)
      carEmployeeMap[key][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)
                  tempMap := carEmployeeMap[key]
                  tempMap[workingHour.WorkerID] = true
                  carEmployeeMap[key] = tempMap
                  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,
@@ -175,14 +191,9 @@
      // 野纤统计
      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 yield.MarketId == check.FinenessRegister.MarketId && yield.WorkshopNumber == check.FinenessRegister.WorkshopNumber && yield.GroupNumber == check.FinenessRegister.WorkshopGroup {
            if strings.Contains(check.FinenessGrade, "野") {
               temp := badSilkQuantityMap[check.FinenessRegister.Position]
               temp[check.FinenessGrade] = temp[check.FinenessGrade] + 1
               badSilkQuantityMap[check.FinenessRegister.Position] = temp
               badSilkQuantityMap[check.FinenessRegister.Position][check.FinenessGrade] += 1
            }
         }
      }
@@ -195,23 +206,23 @@
         if workIdMap, ok := carEmployeeMap[key]; ok {
            result.CarWorkQuantity = len(workIdMap)
            for workId := range workIdMap {
               result.CarWorkIds += workId + ","
               result.CarWorkIds += fmt.Sprintf("%v,", workId)
            }
         }
         // 野纤
         if bad, ok := badSilkQuantityMap[carNumber]; ok {
         if badSilk, ok := badSilkQuantityMap[carNumber]; ok {
            quantityTmp := 0
            totalAmount := decimal.NewFromInt32(0)
            for s := range bad {
               quantityTmp = quantityTmp + bad[s]
            for finenessGrade := range badSilk {
               quantityTmp += badSilk[finenessGrade]
               for _, price := range priceStandards {
                  if price.MarketId == result.MarketId && price.RawSilkGrade == s {
                  if price.MarketId == result.MarketId && price.RawSilkGrade == finenessGrade {
                     result.BadSilkUnitAmount = price.PayStandard
                     totalAmount = totalAmount.Add(result.BadSilkUnitAmount.Mul(decimal.NewFromInt32(int32(bad[s]))))
                     totalAmount = totalAmount.Add(result.BadSilkUnitAmount.Mul(decimal.NewFromInt32(int32(badSilk[finenessGrade]))))
                     continue
                  }
               }
               result.BadSilkType += s + ","
               result.BadSilkType += fmt.Sprintf("%v,", finenessGrade)
            }
            result.BadSilkQuantity = decimal.NewFromInt32(int32(quantityTmp))
@@ -230,12 +241,10 @@
   }
   err = models.WithTransaction(func(db *gorm.DB) error {
      err := models.NewPayrollProductionCarSearch().SetOrm(db).SetCycle(date).Delete()
      if err != nil {
      if err := models.NewPayrollProductionCarSearch().SetOrm(db).SetCycle(date).Delete(); err != nil {
         return err
      }
      err = models.NewPayrollProductionCarSearch().SetOrm(db).CreateBatch(productionCar)
      if err != nil {
      if err = models.NewPayrollProductionCarSearch().SetOrm(db).CreateBatch(productionCar); err != nil {
         return err
      }
      return nil
@@ -255,38 +264,47 @@
      return err
   }
   workingHours, err := models.NewPayrollWorkingHoursSearch().SetWorkTypeCode(constvar.JobTypeWeavers).SetCycle(date).FindNotTotal() // 员工的工时统计
   if err != nil {
      return err
   }
   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
   }
   productionGroupList := make([]*models.PayrollProductionGroup, 0)
   var counter int
   for i := 0; i < len(productionCars); i++ {
      counter = 0
      silkQuantity := decimal.NewFromInt32(0)
      silkAvgQuantity := decimal.NewFromInt32(0)
      silkTotalAmount := decimal.NewFromInt32(0)
      silkTotalAvgAmount := decimal.NewFromInt32(0)
      badSilkQuantity := decimal.NewFromInt32(0)
      badSilkTotalAmount := decimal.NewFromInt32(0)
      badSilkTotalAvgAmount := decimal.NewFromInt32(0)
      finishTotalAmount := decimal.NewFromInt32(0)
      finishTotalAvgAmount := decimal.NewFromInt32(0)
      fallingSilkBucket := decimal.NewFromInt32(0)
      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
            }
            // 一车多人,算平均
            //population := decimal.NewFromInt32(int32(productionCars[j].CarWorkQuantity))
            silkQuantity = silkQuantity.Add(productionCars[j].SilkQuantity)
            silkAvgQuantity = silkAvgQuantity.Add(productionCars[j].SilkAvgQuantity)
            silkTotalAmount = silkTotalAmount.Add(productionCars[j].SilkTotalAmount)
            silkTotalAvgAmount = silkTotalAvgAmount.Add(productionCars[j].SilkTotalAvgAmount)
            badSilkQuantity = badSilkQuantity.Add(productionCars[j].BadSilkQuantity)
            badSilkTotalAmount = badSilkTotalAmount.Add(productionCars[j].BadSilkTotalAmount)
            badSilkTotalAvgAmount = badSilkTotalAvgAmount.Add(productionCars[j].BadSilkTotalAvgAmount)
            finishTotalAmount = finishTotalAmount.Add(productionCars[j].FinishTotalAmount)
            finishTotalAvgAmount = finishTotalAvgAmount.Add(productionCars[j].FinishTotalAvgAmount)
            fallingSilkBucket = fallingSilkBucket.Add(productionCars[j].FallingSilkBucket)
            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)
            counter += 1
            // 跳过重复项
            if i != j {
               i += 1
@@ -294,22 +312,7 @@
         }
      }
      counterD := decimal.NewFromInt32(int32(counter))
      productionGroupList = append(productionGroupList, &models.PayrollProductionGroup{
         Cycle:                 date,
         WorkshopNumber:        productionCars[i].WorkshopNumber,
         GroupNumber:           productionCars[i].GroupNumber,
         FallingSilkBucket:     fallingSilkBucket,
         SilkQuantity:          silkQuantity,
         SilkAvgQuantity:       silkAvgQuantity.Div(counterD),
         SilkTotalAmount:       silkTotalAmount,
         SilkTotalAvgAmount:    silkTotalAmount.Div(counterD),
         BadSilkQuantity:       badSilkQuantity,
         BadSilkTotalAmount:    badSilkTotalAmount,
         BadSilkTotalAvgAmount: badSilkTotalAmount.Div(counterD),
         FinishTotalAmount:     finishTotalAmount,
         FinishTotalAvgAmount:  finishTotalAmount.Div(counterD),
      })
      productionGroupList = append(productionGroupList, &group)
   }
   err = models.WithTransaction(func(db *gorm.DB) error {
@@ -330,18 +333,7 @@
   return nil
}
// 根据上报计算:
//   1、车台当月全等级丝总量;
//   2、车台当月各等级丝总量;
//   3、车台每月等级占比=车台当月各等级丝总量/车台当月全等级丝总量;
//   4、车台每月每人平均丝量=车台当月全等级丝总量/车台挡车工人数;
//   5、车台当月全野纤扣除金额;
//   6、车台每月每人平均野纤扣除金额=当月全野纤扣除金额/车台挡车工人数;
//   7、车台每月丝量总金额
//   8、车台每月丝量成品金额
//   9、车台每月每人平均丝量金额=车台每月丝量成品金额/车台挡车工人数
// ProductionEmployee 存表: 每人每天的产量统计登记
// ProductionWeavers 存表: 挡车工每人每天的产量统计登记
func ProductionWeavers(date string) error {
   workingHours, err := models.NewPayrollWorkingHoursSearch().SetWorkTypeCode(constvar.JobTypeWeavers).SetCycle(date).FindNotTotal() // 员工的工时统计
   if err != nil {
@@ -359,6 +351,7 @@
         Cycle:          date,
         WorkTypeID:     worker.WorkTypeID,
         WorkerID:       worker.WorkerID,
         WorkshopId:     worker.WorkshopId,
         WorkshopNumber: worker.WorkshopNumber,
         GroupNumber:    worker.GroupNumber,
      }
@@ -377,12 +370,10 @@
   }
   err = models.WithTransaction(func(db *gorm.DB) error {
      err := models.NewPayrollProductionWeaversSearch().SetOrm(db).SetCycle(date).Delete()
      if err != nil {
      if err := models.NewPayrollProductionWeaversSearch().SetOrm(db).SetCycle(date).Delete(); err != nil {
         return err
      }
      err = models.NewPayrollProductionWeaversSearch().SetOrm(db).CreateBatch(productionEmployee)
      if err != nil {
      if err = models.NewPayrollProductionWeaversSearch().SetOrm(db).CreateBatch(productionEmployee); err != nil {
         return err
      }
      return nil
@@ -391,23 +382,19 @@
   return nil
}
// 存表:工资计算(日期(年月)、工种、员工姓名、小组、车台、生产工资、满勤奖(=配置)、超时工资(=上班超时小时*5+上班超时天*6)、加班工资(=单独加班*80+全车间加班*75)、交通补贴(=1*出勤天数)、带徒补贴(=5*带徒天数)、
//            岗位补贴(=配置)、社保补贴(=配置)、工龄补贴(=配置)、不达保底(=配置保底)、质量奖、奖罚1、奖罚2/清凉补贴、奖罚3/日常检查、停机补贴、应发工资、备注)
type SalaryParameter struct {
   SilkQuantity       decimal.Decimal // 日产丝量
   SilkUnitAmount     decimal.Decimal // 生丝单价
   SilkTotalAmount    decimal.Decimal // 生丝总价(=日产丝量*生丝单价)
   FallingSilkBucket  decimal.Decimal // 桶数
   BadSilkQuantity    decimal.Decimal // 野纤数量
   BadSilkUnitAmount  decimal.Decimal // 野纤单价
   BadSilkTotalAmount decimal.Decimal // 野纤总价
// OtherSubsidies 存表: 其它补贴
func OtherSubsidies(date string) error {
   models.NewPayrollOtherSubsidiesSearch() // 其它补贴
   return nil
   GroupCarHeadAvgAmount decimal.Decimal // 同组车头工工资
   GroupWeaversAvgAmount decimal.Decimal // 同组挡车工月平均工资
   JobDays               decimal.Decimal // 出勤天数
}
// 存表:自动缫车间各挡车、车头、保全生产工资计算 (日期(年月)、车间、组别、车台、个人产量(车台每月每人平均丝量)、挡车工工资(车台每月每人平均丝量金额))
// 根据上报计算:
//    1、挡车工平均工资(以组为单位)= 每月小组每车头工资之和/6(70绪)
//   2、车头工工资(以组为单位)= 挡车工平均工资*1.09(1.09为指定系数)
//   3、保全工工资(以组为单位)= (挡车工平均工资+车头工工资)/2*1.2(1.2为指定系数)
//   4、折100绪挡车平均工资(以组为单位)= 每月小组每车头工资之和/4(100绪)
// SalaryPlan 生产工资计算
func SalaryPlan(date string) error {
@@ -417,83 +404,216 @@
      date = date[:7]
   }
   hours, err := models.NewPayrollWorkingHoursSearch().SetMonthly(date).FindNotTotal() // 员工的工时统计
   hours, err := models.NewPayrollWorkingHoursSearch().SetOrder("worker_id").SetMonthly(date).FindNotTotal() // 员工的工时统计
   if err != nil {
      return err
   }
   groups, err := models.NewPayrollProductionGroupSearch().SetOrder("workshop_number,groupnumber").
      SetMonthly(date).FindNotTotal() // 小组每天的产量统计
   if err != nil {
      return err
   jobQuantityMap := make(map[string]int) // 员工出勤统计
   for _, hour := range hours {
      jobQuantityMap[hour.WorkerID] += 1
   }
   // 每个小组的平均金额
   groupAvgAmountMap := make(map[string]decimal.Decimal)    // map[车间小组]平均金额
   fallingSilkBucketMap := make(map[string]decimal.Decimal) // map[车间小组] FallingSilkBucket
   var counter int
   for i := 0; i < len(groups); i++ {
      counter = 0
      groupAvgAmount := decimal.NewFromInt32(0)
      fallingSilkBucket := decimal.NewFromInt32(0)
      for j := i; j < len(groups); j++ {
         if groups[i].WorkshopNumber == groups[j].WorkshopNumber && groups[i].GroupNumber == groups[j].GroupNumber {
            groupAvgAmount = groupAvgAmount.Add(groups[j].FinishTotalAvgAmount)
            fallingSilkBucket = fallingSilkBucket.Add(groups[j].FallingSilkBucket)
            counter += 1
            if i != j {
               i += 1
            }
         }
      }
      key := fmt.Sprintf("%v%v", groups[i].WorkshopNumber, groups[i].GroupNumber)
      groupAvgAmountMap[key] = groupAvgAmount.Div(decimal.NewFromInt32(int32(counter)))
      fallingSilkBucketMap[key] = fallingSilkBucket
   workers, err := models.NewWorkerSearch().FindNotTotal()
   workerMap := make(map[string]*models.Worker)
   for _, worker := range workers {
      workerMap[worker.ID] = worker
   }
   // 挡车工工资
   models.NewPayrollProductionWeaversSearch().Orm.Model(&models.PayrollProductionWeavers{}).
      Select("worker_id,sum()").Where("cycle like ?", date+"%")
   weaversAmountArr, _ := models.NewPayrollProductionWeaversSearch().SetMonthly(date).FindNotTotal()
   weaversAmountMap := make(map[string]*models.PayrollProductionWeavers, len(weaversAmountArr))
   for _, weaver := range weaversAmountArr {
      key := fmt.Sprintf("%v%v", weaver.Cycle, weaver.WorkerID)
      weaversAmountMap[key] = weaver
   }
   // 查询单价
   for _, hour := range hours {
      key := fmt.Sprintf("%v%v", hour.WorkshopNumber, hour.GroupNumber)
   // 工种工资方案 map[工种]方案
   salaryPlans, _ := models.NewWorkTypeManageSearch().FindNotTotal()
   salaryPlansMap := make(map[uint]*models.WorkTypeManage, len(salaryPlans))
   for _, salaryPlan := range salaryPlans {
      salaryPlansMap[salaryPlan.ID] = salaryPlan
   }
      ready70 := decimal.NewFromInt32(6)
      ready100 := decimal.NewFromInt32(4)
      coefficient := decimal.NewFromInt32(1)
      switch hour.WorkTypeCode {
      case constvar.JobTypeWeavers: // 日产量工资=(生丝单价*日产丝量)-(野纤数量*野纤单价)   月产量工资=日产量工资之和
         coefficient.Mul(coefficient).Sub(coefficient.Mul(coefficient))
   groups, err := models.NewPayrollProductionGroupSearch().SetMonthly(date).FindNotTotal()
   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
      case constvar.JobTypeCarHead: // 月工资=70绪挡车工月平均工资*系数
         groupAvgAmountMap[key].Div(ready70).Mul(coefficient)
      case constvar.JobTypeMaintenance: // 月工资=(70绪挡车工月平均工资)+车头工工资)/2*系数 ???? excel上的是【挡车工月平均工资*系数】
         groupAvgAmountMap[key].Div(ready70).Mul(coefficient)
      case constvar.JobTypeBoiled: // 日工资=桶数*煮茧单价  月工资=日工资之和
         fallingSilkBucketMap[key].Mul(coefficient)
      case constvar.JobTypeScoop: // 日工资=桶数*舀茧单价 月工资=日工资之和
         fallingSilkBucketMap[key].Mul(coefficient)
      case constvar.JobTypeTransport: // 日工资=桶数*送茧单价   月工资=日工资之和
         fallingSilkBucketMap[key].Mul(coefficient)
      case constvar.JobTypeCleaner: // 月工资=固定工资*出勤天数
         coefficient.Mul(coefficient)
      case constvar.JobTypeMachineCleaner: // 月工资=固定工资*出勤天数
         coefficient.Mul(coefficient)
      case constvar.JobTypeAllPowerful: // 月工资=固定工资*出勤天数
         coefficient.Mul(coefficient)
      case constvar.JobTypeMonitor: // 100绪挡车工平均工资*系数
         groupAvgAmountMap[key].Div(ready100).Mul(coefficient)
      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)
      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)
               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 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",
      }
      monthKey := fmt.Sprintf("%v%v", worker.ShopNumber, worker.GroupNumber)
      group := groupByMonthMap[monthKey]
      parameter := SalaryParameter{
         FallingSilkBucket:     group.FallingSilkBucket,
         GroupWeaversAvgAmount: group.FinishTotalAvgAmount,
         GroupCarHeadAvgAmount: group.FinishTotalAvgAmount.Div(ready70),
         JobDays:               decimal.NewFromInt32(int32(dayCount)),
      }
      // 按月算:同组挡车工月平均工资、同组车头工工资、出勤天数
      if workType, ok := salaryPlansMap[worker.WorkTypeId]; ok {
         for _, salaryPlan := range workType.SalaryPlans {
            if matched, _ := regexp.MatchString("(同组挡车工月平均工资)|(同组车头工工资)|(出勤天数)", salaryPlan.SalaryFormula); matched {
               temp := constitute
               formula, s := salaryCalculate(&parameter, 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 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, " ", "")
   //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)
   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)
}