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)
|
}
|