package service
|
|
import (
|
"errors"
|
"fmt"
|
"github.com/shopspring/decimal"
|
"gorm.io/gorm"
|
"silkserver/constvar"
|
"silkserver/models"
|
"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 {
|
// 人员信息
|
workers, err := models.NewWorkerSearch().FindNotTotal()
|
if err != nil {
|
return err
|
}
|
|
// 排班信息(功能缺失)
|
// 打卡信息(通过人员关联)
|
attendances, err := models.NewAttendanceManageSearch().SetDate(date).FindNotTotal()
|
|
// 车台信息(通过人员关联)
|
workerPositions, err := models.NewWorkerPositionSearch().SetOverlappingDate(date, date).FindAll()
|
|
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
|
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 {
|
|
models.NewPayrollWorkingHoursSearch().SetOrm(db).SetCycle(date).Delete()
|
|
models.NewPayrollWorkingHoursSearch().SetOrm(db).CreateBatch(list)
|
return nil
|
})
|
|
return nil
|
}
|
|
// ProductionCar 存表:车台每日产量统计 (日期(年月日)、车间、车台、庄口、期望等级、成品等级、丝量、丝单价(json)、野纤、野纤单价(json)、丝量金额、野纤金额、成品金额(丝量金额-野纤金额))
|
func ProductionCar(date string) error {
|
yieldRegisters, err := models.NewYieldRegisterSearch().SetCreateTime(date).FindNotTotal() // 产量登记
|
if err != nil {
|
return err
|
}
|
finenesss, err := models.NewFinenessRegisterSearch().SetFinishDate(date).FindAll() // 纤度登记
|
if err != nil {
|
return err
|
}
|
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, _ := models.NewRawSilkPriceStandardSearch().FindNotTotal() // 生丝定价
|
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
|
}
|
|
// 车台挡车工重复人员标记
|
carEmployeeMap := make(map[string]map[string]bool) // map[车间\组别\车号]map[人员]true
|
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
|
}
|
}
|
}
|
}
|
}
|
|
productionCar := make([]*models.PayrollProductionCar, 0)
|
for _, yield := range yieldRegisters {
|
info := models.PayrollProductionCar{
|
Cycle: date,
|
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, "野") {
|
temp := badSilkQuantityMap[check.FinenessRegister.Position]
|
temp[check.FinenessGrade] = temp[check.FinenessGrade] + 1
|
badSilkQuantityMap[check.FinenessRegister.Position] = temp
|
}
|
}
|
}
|
|
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 += workId + ","
|
}
|
}
|
// 野纤
|
if bad, ok := badSilkQuantityMap[carNumber]; ok {
|
quantityTmp := 0
|
totalAmount := decimal.NewFromInt32(0)
|
for s := range bad {
|
quantityTmp = quantityTmp + bad[s]
|
for _, price := range priceStandards {
|
if price.MarketId == result.MarketId && price.RawSilkGrade == s {
|
result.BadSilkUnitAmount = price.PayStandard
|
totalAmount = totalAmount.Add(result.BadSilkUnitAmount.Mul(decimal.NewFromInt32(int32(bad[s]))))
|
continue
|
}
|
}
|
result.BadSilkType += s + ","
|
}
|
|
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 {
|
err := models.NewPayrollProductionCarSearch().SetOrm(db).SetCycle(date).Delete()
|
if err != nil {
|
return err
|
}
|
err = models.NewPayrollProductionCarSearch().SetOrm(db).CreateBatch(productionCar)
|
if 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
|
}
|
|
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)
|
|
for j := i; j < len(productionCars); j++ {
|
if productionCars[i].WorkshopNumber == productionCars[j].WorkshopNumber &&
|
productionCars[i].GroupNumber == productionGroupList[j].GroupNumber {
|
// 一车多人,算平均
|
//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)
|
|
counter += 1
|
// 跳过重复项
|
if i != j {
|
i += 1
|
}
|
}
|
|
}
|
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),
|
})
|
}
|
|
err = models.WithTransaction(func(db *gorm.DB) error {
|
err := models.NewPayrollProductionGroupSearch().SetOrm(db).SetCycle(date).Delete()
|
if err != nil {
|
return err
|
}
|
err = models.NewPayrollProductionGroupSearch().SetOrm(db).CreateBatch(productionGroupList)
|
if err != nil {
|
return err
|
}
|
return nil
|
})
|
if err != nil {
|
return err
|
}
|
|
return nil
|
}
|
|
// 根据上报计算:
|
// 1、车台当月全等级丝总量;
|
// 2、车台当月各等级丝总量;
|
// 3、车台每月等级占比=车台当月各等级丝总量/车台当月全等级丝总量;
|
// 4、车台每月每人平均丝量=车台当月全等级丝总量/车台挡车工人数;
|
// 5、车台当月全野纤扣除金额;
|
// 6、车台每月每人平均野纤扣除金额=当月全野纤扣除金额/车台挡车工人数;
|
// 7、车台每月丝量总金额
|
// 8、车台每月丝量成品金额
|
// 9、车台每月每人平均丝量金额=车台每月丝量成品金额/车台挡车工人数
|
|
// ProductionEmployee 存表: 每人每天的产量统计登记
|
func ProductionWeavers(date string) error {
|
workingHours, err := models.NewPayrollWorkingHoursSearch().SetWorkTypeCode(constvar.JobTypeWeavers).SetCycle(date).FindNotTotal() // 员工的工时统计
|
if err != nil {
|
return err
|
}
|
|
productionCars, err := models.NewPayrollProductionCarSearch().SetCycle(date).FindNotTotal()
|
if err != nil {
|
return err
|
}
|
|
productionEmployee := make([]*models.PayrollProductionWeavers, 0)
|
for _, worker := range workingHours {
|
info := models.PayrollProductionWeavers{
|
Cycle: date,
|
WorkTypeID: worker.WorkTypeID,
|
WorkerID: worker.WorkerID,
|
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)
|
}
|
}
|
productionEmployee = append(productionEmployee, &info)
|
}
|
|
err = models.WithTransaction(func(db *gorm.DB) error {
|
err := models.NewPayrollProductionWeaversSearch().SetOrm(db).SetCycle(date).Delete()
|
if err != nil {
|
return err
|
}
|
err = models.NewPayrollProductionWeaversSearch().SetOrm(db).CreateBatch(productionEmployee)
|
if err != nil {
|
return err
|
}
|
return nil
|
})
|
|
return nil
|
}
|
|
// 存表:工资计算(日期(年月)、工种、员工姓名、小组、车台、生产工资、满勤奖(=配置)、超时工资(=上班超时小时*5+上班超时天*6)、加班工资(=单独加班*80+全车间加班*75)、交通补贴(=1*出勤天数)、带徒补贴(=5*带徒天数)、
|
// 岗位补贴(=配置)、社保补贴(=配置)、工龄补贴(=配置)、不达保底(=配置保底)、质量奖、奖罚1、奖罚2/清凉补贴、奖罚3/日常检查、停机补贴、应发工资、备注)
|
|
// OtherSubsidies 存表: 其它补贴
|
func OtherSubsidies(date string) error {
|
|
models.NewPayrollOtherSubsidiesSearch() // 其它补贴
|
|
return nil
|
}
|
|
// 存表:自动缫车间各挡车、车头、保全生产工资计算 (日期(年月)、车间、组别、车台、个人产量(车台每月每人平均丝量)、挡车工工资(车台每月每人平均丝量金额))
|
// 根据上报计算:
|
// 1、挡车工平均工资(以组为单位)= 每月小组每车头工资之和/6(70绪)
|
// 2、车头工工资(以组为单位)= 挡车工平均工资*1.09(1.09为指定系数)
|
// 3、保全工工资(以组为单位)= (挡车工平均工资+车头工工资)/2*1.2(1.2为指定系数)
|
// 4、折100绪挡车平均工资(以组为单位)= 每月小组每车头工资之和/4(100绪)
|
|
// SalaryPlan 生产工资计算
|
func SalaryPlan(date string) error {
|
if len(date) < 7 {
|
return errors.New("请传入正确的查询时间!")
|
} else {
|
date = date[:7]
|
}
|
|
hours, err := models.NewPayrollWorkingHoursSearch().SetMonthly(date).FindNotTotal() // 员工的工时统计
|
if err != nil {
|
return err
|
}
|
groups, err := models.NewPayrollProductionGroupSearch().SetOrder("workshop_number,groupnumber").
|
SetMonthly(date).FindNotTotal() // 小组每天的产量统计
|
if err != nil {
|
return err
|
}
|
// 每个小组的平均金额
|
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
|
}
|
|
// 挡车工工资
|
models.NewPayrollProductionWeaversSearch().Orm.Model(&models.PayrollProductionWeavers{}).
|
Select("worker_id,sum()").Where("cycle like ?", date+"%")
|
|
// 查询单价
|
for _, hour := range hours {
|
key := fmt.Sprintf("%v%v", hour.WorkshopNumber, hour.GroupNumber)
|
|
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))
|
|
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)
|
|
}
|
|
}
|
|
return nil
|
}
|