liujiandao
2024-04-30 76a84d89d63041232c646ca28c59239dd00f7fc5
薪资计算
7个文件已添加
12个文件已修改
831 ■■■■■ 已修改文件
constvar/const.go 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/attendance_controller.go 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/report_forms_controller.go 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/request/report_forms_request.go 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/request/worker_request.go 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/response/report_forms_response.go 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/salary_plan_controller.go 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
go.mod 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
go.sum 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/attendance_manage.go 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/mini_dict.go 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/raw_silk_price_standard.go 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/salary_details.go 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/salary_plan.go 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/salary_report_form.go 163 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/work_type_manage.go 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/yield_register_item.go 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
task/salary_statistics.go 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
utils/salary_calculate.go 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
constvar/const.go
@@ -107,3 +107,21 @@
    FileTemplateCategory_JialianOutput     = 15                            //嘉联出库
    FileTemplateCategory_JialianAttendance = 16                            //嘉联-员工考勤
)
const (
    DailySilkProduction     = "日产丝量"
    WasteSilkQuantity       = "野纤数量"
    RawSilkUnitPrice        = "生丝单价"
    WasteSilkUnitPrice      = "野纤单价"
    BucketCount             = "桶数(日)"
    AttendanceDays          = "出勤天数"
    GroupAverageMonthlyWage = "同组挡车工月平均工资"
    GroupCarHeadWage        = "同组车头工工资"
    WeekdayOvertimeHours    = "工作日加班时长"
    FullAttendanceAward     = "满勤奖"
    WeekendOvertimeHours    = "休息日加班时长"
    LeaveDays               = "请假天数"
    ApprenticeDays          = "带徒天数"
    TotalAttendanceDays     = "出勤天数"
    Seniority               = "工龄"
)
controllers/attendance_controller.go
@@ -114,6 +114,7 @@
        for _, worker := range workers {
            if attendance.WorkerId == worker.ID {
                attendance.WorkTypeId = worker.WorkTypeId
                attendance.PhoneNum = worker.PhoneNum
                break
            }
        }
controllers/report_forms_controller.go
New file
@@ -0,0 +1,32 @@
package controllers
import (
    "github.com/gin-gonic/gin"
)
type ReportFormsController struct {
}
// SalaryReportForms
//
//    @Tags        报表管理
//    @Summary    薪资报表
//    @Produce    application/json
//    @Param        object    body        request.SalaryReportForms    true    "参数"
//    @Param         Authorization    header string true "token"
//    @Success    200        {object}    util.ResponseList{data=[]models.WorkTypeManage}        "成功"
//    @Router        /api-jl/v1/forms/salaryReportForms [post]
func (slf ReportFormsController) SalaryReportForms(c *gin.Context) {
    //var params request.SalaryReportForms
    //err := c.BindJSON(&params)
    //if err != nil {
    //    util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误")
    //    return
    //}
    //workers, err := models.NewWorkerSearch().SetPage(params.Page, params.PageSize).FindNotTotal()
    //if err != nil {
    //    util.ResponseFormat(c, code.RequestParamError, err)
    //    return
    //}
}
controllers/request/report_forms_request.go
New file
@@ -0,0 +1,6 @@
package request
type SalaryReportForms struct {
    PageInfo
    Month string `json:"month"`
}
controllers/request/worker_request.go
@@ -23,6 +23,7 @@
}
type SalaryTypeValue struct {
    Id        uint   `json:"id"`
    Name      string `json:"name"`      //名称
    IsDefault bool   `json:"isDefault"` //是否可编辑
}
controllers/response/report_forms_response.go
New file
@@ -0,0 +1,8 @@
package response
type SalaryReportForms struct {
    WorkerName string `json:"workerName"`
    WorkerId   string `json:"workerId"`
    Phone      string `json:"phone"`
    WorkType   string `json:"workType"`
}
controllers/salary_plan_controller.go
@@ -127,23 +127,75 @@
        util.ResponseFormat(c, code.RequestParamError, "类型不能为空")
        return
    }
    types := make([]*models.MiniDict, 0)
    for _, value := range params.Values {
    miniDicts, err := models.NewMiniDictSearch().SetType(params.Type).FindNotTotal()
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, err)
        return
    }
    dicts := params.Values
    add := make([]*models.MiniDict, 0)
    del := make([]uint, 0)
    update := make([]*models.MiniDict, 0)
    for _, mini := range miniDicts {
        flag := true
        for i, value := range dicts {
            var dict models.MiniDict
            dict.Name = value.Name
            dict.IsDefault = value.IsDefault
            dict.Type = params.Type
            if value.Id == 0 {
                add = append(add, &dict)
                flag = false
                if i < len(dicts)-1 {
                    dicts = append(dicts[:i], dicts[i+1:]...)
                } else {
                    dicts = dicts[:i]
                }
                break
            } else if value.Id == mini.ID {
                update = append(update, &dict)
                flag = false
                if i < len(dicts)-1 {
                    dicts = append(dicts[:i], dicts[i+1:]...)
                } else {
                    dicts = dicts[:i]
                }
                break
            }
        }
        if flag {
            del = append(del, mini.ID)
        }
    }
    //新增的
    for _, value := range dicts {
        var dict models.MiniDict
        dict.Name = value.Name
        dict.IsDefault = value.IsDefault
        dict.Type = params.Type
        types = append(types, &dict)
        add = append(add, &dict)
    }
    err = models.WithTransaction(func(db *gorm.DB) error {
        err = models.NewMiniDictSearch().SetOrm(db).SetType(params.Type).Delete()
        if err != nil {
            return err
        if len(del) > 0 {
            err = models.NewMiniDictSearch().SetOrm(db).SetIds(del).Delete()
            if err != nil {
                return err
            }
        }
        err = models.NewMiniDictSearch().SetOrm(db).CreateBatch(types)
        if err != nil {
            return err
        if len(update) > 0 {
            err = models.NewMiniDictSearch().SetOrm(db).SaveBatch(update)
            if err != nil {
                return err
            }
        }
        if len(add) > 0 {
            err = models.NewMiniDictSearch().SetOrm(db).CreateBatch(add)
            if err != nil {
                return err
            }
        }
        return nil
    })
    if err != nil {
go.mod
@@ -4,11 +4,13 @@
require (
    basic.com/aps/nsqclient.git v0.0.0-20230517072415-37491f4a5d25
    github.com/Knetic/govaluate v3.0.0+incompatible
    github.com/dgrijalva/jwt-go v3.2.0+incompatible
    github.com/gin-gonic/gin v1.9.1
    github.com/golang-jwt/jwt/v4 v4.5.0
    github.com/nsqio/go-nsq v1.1.0
    github.com/shopspring/decimal v1.3.1
    github.com/spf13/cast v1.6.0
    github.com/spf13/viper v1.18.2
    github.com/swaggo/files v1.0.1
    github.com/swaggo/gin-swagger v1.6.0
@@ -64,7 +66,6 @@
    github.com/sagikazarmark/slog-shim v0.1.0 // indirect
    github.com/sourcegraph/conc v0.3.0 // indirect
    github.com/spf13/afero v1.11.0 // indirect
    github.com/spf13/cast v1.6.0 // indirect
    github.com/spf13/pflag v1.0.5 // indirect
    github.com/subosito/gotenv v1.6.0 // indirect
    github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
go.sum
@@ -1,5 +1,7 @@
basic.com/aps/nsqclient.git v0.0.0-20230517072415-37491f4a5d25 h1:sZyNfIISgP1eoY94LG48Kav6HYVLem6EzaEbCeXlcXQ=
basic.com/aps/nsqclient.git v0.0.0-20230517072415-37491f4a5d25/go.mod h1:1RnwEtePLR7ATQorQTxdgvs1o7uuUy1Vw8W7GYtVnoY=
github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg=
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
models/attendance_manage.go
@@ -26,6 +26,7 @@
        WorkType         WorkTypeManage            `json:"workType" gorm:"foreignKey:WorkTypeId"`
        Status           constvar.AttendanceStatus `json:"status" gorm:"type:int(11);comment:状态"`
        OverTimeDuration decimal.Decimal           `json:"overTimeDuration" gorm:"type:decimal(20,2);comment:加班时长"`
        PhoneNum         string                    `gorm:"type:varchar(191);comment:手机号" json:"phoneNum"`
    }
    AttendanceManageSearch struct {
        AttendanceManage
models/mini_dict.go
@@ -20,6 +20,7 @@
    MiniDictSearch struct {
        MiniDict
        Order    string
        Ids      []uint
        PageNum  int
        PageSize int
        Orm      *gorm.DB
@@ -54,6 +55,11 @@
    return slf
}
func (slf *MiniDictSearch) SetIds(ids []uint) *MiniDictSearch {
    slf.Ids = ids
    return slf
}
func (slf *MiniDictSearch) SetType(tp constvar.MiniDictType) *MiniDictSearch {
    slf.Type = tp
    return slf
@@ -74,6 +80,10 @@
    if slf.ID > 0 {
        db = db.Where("id = ?", slf.ID)
    }
    if len(slf.Ids) > 0 {
        db = db.Where("id in (?)", slf.Ids)
    }
    if slf.Type > 0 {
@@ -128,6 +138,16 @@
    return nil
}
func (slf *MiniDictSearch) SaveBatch(record []*MiniDict) error {
    var db = slf.build()
    if err := db.Omit("CreatedAt").Save(record).Error; err != nil {
        return fmt.Errorf("save err: %v, record: %+v", err, record)
    }
    return nil
}
func (slf *MiniDictSearch) UpdateByMap(upMap map[string]interface{}) error {
    var (
        db = slf.build()
models/raw_silk_price_standard.go
@@ -20,10 +20,11 @@
    }
    RawSilkPriceStandardSearch struct {
        RawSilkPriceStandard
        Order    string
        PageNum  int
        PageSize int
        Orm      *gorm.DB
        Order       string
        PageNum     int
        PageSize    int
        MarketNames []string
        Orm         *gorm.DB
    }
)
@@ -55,6 +56,11 @@
    return slf
}
func (slf *RawSilkPriceStandardSearch) SetMarketNames(names []string) *RawSilkPriceStandardSearch {
    slf.MarketNames = names
    return slf
}
func (slf *RawSilkPriceStandardSearch) build() *gorm.DB {
    db := slf.Orm.Table(slf.TableName())
@@ -62,6 +68,10 @@
        db = db.Where("id = ?", slf.ID)
    }
    if len(slf.MarketNames) > 0 {
        db = db.Where("market_name in (?)", slf.MarketNames)
    }
    return db
}
models/salary_details.go
New file
@@ -0,0 +1,158 @@
package models
import (
    "fmt"
    "github.com/shopspring/decimal"
    "gorm.io/gorm"
    "silkserver/pkg/mysqlx"
)
type (
    //SalaryDetails 薪资明细表
    SalaryDetails struct {
        gorm.Model
        SalaryDetailsId uint            `json:"SalaryDetailsId" gorm:"type:int(11);comment:薪资报表id"`
        SalaryTypeId    uint            `json:"salaryTypeId" gorm:"type:int(11);comment:薪资类型id"`
        SalaryType      MiniDict        `json:"salaryType" gorm:"foreignKey:SalaryTypeId;references:ID"`
        Amount          decimal.Decimal `json:"amount" gorm:"type:decimal(20,3);comment:工资值"`
    }
    SalaryDetailsSearch struct {
        SalaryDetails
        PageNum  int
        PageSize int
        Preload  bool
        Orm      *gorm.DB
    }
)
func (slf SalaryDetails) TableName() string {
    return "salary_details"
}
func NewSalaryDetailsSearch() *SalaryDetailsSearch {
    return &SalaryDetailsSearch{Orm: mysqlx.GetDB()}
}
func (slf *SalaryDetailsSearch) SetOrm(tx *gorm.DB) *SalaryDetailsSearch {
    slf.Orm = tx
    return slf
}
func (slf *SalaryDetailsSearch) SetPage(page, size int) *SalaryDetailsSearch {
    slf.PageNum, slf.PageSize = page, size
    return slf
}
func (slf *SalaryDetailsSearch) SetPreload(preload bool) *SalaryDetailsSearch {
    slf.Preload = preload
    return slf
}
func (slf *SalaryDetailsSearch) build() *gorm.DB {
    var db = slf.Orm.Table(slf.TableName())
    if slf.Preload {
        db = db.Model(SalaryDetails{}).Preload("SalaryType")
    }
    return db
}
// Create 单条插入
func (slf *SalaryDetailsSearch) Create(record *SalaryDetails) error {
    var db = slf.build()
    if err := db.Create(record).Error; err != nil {
        return fmt.Errorf("create err: %v, record: %+v", err, record)
    }
    return nil
}
// CreateBatch 批量插入
func (slf *SalaryDetailsSearch) CreateBatch(record []*SalaryDetails) error {
    var db = slf.build()
    if err := db.Create(record).Error; err != nil {
        return fmt.Errorf("create err: %v, record: %+v", err, record)
    }
    return nil
}
func (slf *SalaryDetailsSearch) Save(record *SalaryDetails) error {
    var db = slf.build()
    if err := db.Omit("CreatedAt").Save(record).Error; err != nil {
        return fmt.Errorf("save err: %v, record: %+v", err, record)
    }
    return nil
}
func (slf *SalaryDetailsSearch) UpdateByMap(upMap map[string]interface{}) error {
    var (
        db = slf.build()
    )
    if err := db.Updates(upMap).Error; err != nil {
        return fmt.Errorf("update by map err: %v, upMap: %+v", err, upMap)
    }
    return nil
}
func (slf *SalaryDetailsSearch) Delete() error {
    var db = slf.build()
    if err := db.Unscoped().Delete(&SalaryDetails{}).Error; err != nil {
        return err
    }
    return nil
}
func (slf *SalaryDetailsSearch) Find() ([]*SalaryDetails, int64, error) {
    var (
        records = make([]*SalaryDetails, 0)
        total   int64
        db      = slf.build()
    )
    if err := db.Count(&total).Error; err != nil {
        return records, total, fmt.Errorf("find count err: %v", err)
    }
    if slf.PageNum*slf.PageSize > 0 {
        db = db.Offset((slf.PageNum - 1) * slf.PageSize).Limit(slf.PageSize)
    }
    if err := db.Find(&records).Error; err != nil {
        return records, total, fmt.Errorf("find records err: %v", err)
    }
    return records, total, nil
}
func (slf *SalaryDetailsSearch) FindNotTotal() ([]*SalaryDetails, error) {
    var (
        records = make([]*SalaryDetails, 0)
        db      = slf.build()
    )
    if err := db.Find(&records).Error; err != nil {
        return records, fmt.Errorf("find records err: %v", err)
    }
    return records, nil
}
func (slf *SalaryDetailsSearch) Count() (int64, error) {
    var (
        total int64
        db    = slf.build()
    )
    if err := db.Count(&total).Error; err != nil {
        return total, fmt.Errorf("find count err: %v", err)
    }
    return total, nil
}
models/salary_plan.go
@@ -10,8 +10,10 @@
    //SalaryPlan 薪资方案
    SalaryPlan struct {
        gorm.Model
        Name          string            `json:"name" gorm:"type:varchar(255);comment:薪资方案名称"`
        SalaryType    string            `json:"salaryType" gorm:"type:varchar(255);comment:薪资类型"`
        Name         string   `json:"name" gorm:"type:varchar(255);comment:薪资方案名称"`
        SalaryTypeId uint     `json:"salaryTypeId" gorm:"type:int(11);comment:薪资类型id"`
        SalaryType   MiniDict `json:"salaryType" gorm:"foreignKey:SalaryTypeId;references:ID"`
        //SalaryType    string            `json:"salaryType" gorm:"type:varchar(255);comment:薪资类型"`
        SalaryFormula string            `json:"salaryFormula" gorm:"type:varchar(255);comment:薪资公式"`
        Cycle         string            `json:"cycle" gorm:"type:varchar(255);comment:周期"`
        CreateTime    string            `json:"createTime" gorm:"type:varchar(255);comment:添加时间"`
@@ -63,7 +65,7 @@
    }
    if slf.Preload {
        db = db.Model(&SalaryPlan{}).Preload("WorkTypes")
        db = db.Model(&SalaryPlan{}).Preload("WorkTypes").Preload("SalaryType")
    }
    return db
models/salary_report_form.go
New file
@@ -0,0 +1,163 @@
package models
import (
    "fmt"
    "github.com/shopspring/decimal"
    "gorm.io/gorm"
    "silkserver/pkg/mysqlx"
)
type (
    // SalaryReportForm 薪资报表
    SalaryReportForm struct {
        gorm.Model
        WorkerId    string          `json:"workerId" gorm:"type:varchar(255);comment:人员id"`
        WorkerName  string          `json:"workerName"  gorm:"type:varchar(255);comment:人员姓名"`
        Phone       string          `json:"phone" gorm:"type:varchar(255);comment:电话"`
        WorkTypeId  uint            `json:"workTypeId" gorm:"type:int(11);comment:工种类型id"`
        WorkType    WorkTypeManage  `json:"workType"  gorm:"foreignKey:WorkTypeId;references:ID"`
        Month       string          `json:"month" gorm:"type:varchar(255);comment:月份"`
        IssueSalary decimal.Decimal `json:"issueSalary" gorm:"type:decimal(20,3);comment:应发工资"`
        Remark      string          `json:"remark" gorm:"type:varchar(255);comment:备注"`
        Details     []SalaryDetails `json:"details" gorm:"foreignKey:SalaryReportFormId;references:Id"`
    }
    SalaryReportFormSearch struct {
        SalaryReportForm
        PageNum  int
        PageSize int
        Preload  bool
        Orm      *gorm.DB
    }
)
func (slf SalaryReportForm) TableName() string {
    return "salary_report_form"
}
func NewSalaryReportFormSearch() *SalaryReportFormSearch {
    return &SalaryReportFormSearch{Orm: mysqlx.GetDB()}
}
func (slf *SalaryReportFormSearch) SetOrm(tx *gorm.DB) *SalaryReportFormSearch {
    slf.Orm = tx
    return slf
}
func (slf *SalaryReportFormSearch) SetPage(page, size int) *SalaryReportFormSearch {
    slf.PageNum, slf.PageSize = page, size
    return slf
}
func (slf *SalaryReportFormSearch) SetPreload(preload bool) *SalaryReportFormSearch {
    slf.Preload = preload
    return slf
}
func (slf *SalaryReportFormSearch) build() *gorm.DB {
    var db = slf.Orm.Table(slf.TableName())
    if slf.Preload {
        db = db.Model(SalaryReportForm{}).Preload("Details").Preload("WorkType")
    }
    return db
}
// Create 单条插入
func (slf *SalaryReportFormSearch) Create(record *SalaryReportForm) error {
    var db = slf.build()
    if err := db.Create(record).Error; err != nil {
        return fmt.Errorf("create err: %v, record: %+v", err, record)
    }
    return nil
}
// CreateBatch 批量插入
func (slf *SalaryReportFormSearch) CreateBatch(record []*SalaryReportForm) error {
    var db = slf.build()
    if err := db.Create(record).Error; err != nil {
        return fmt.Errorf("create err: %v, record: %+v", err, record)
    }
    return nil
}
func (slf *SalaryReportFormSearch) Save(record *SalaryReportForm) error {
    var db = slf.build()
    if err := db.Omit("CreatedAt").Save(record).Error; err != nil {
        return fmt.Errorf("save err: %v, record: %+v", err, record)
    }
    return nil
}
func (slf *SalaryReportFormSearch) UpdateByMap(upMap map[string]interface{}) error {
    var (
        db = slf.build()
    )
    if err := db.Updates(upMap).Error; err != nil {
        return fmt.Errorf("update by map err: %v, upMap: %+v", err, upMap)
    }
    return nil
}
func (slf *SalaryReportFormSearch) Delete() error {
    var db = slf.build()
    if err := db.Unscoped().Delete(&SalaryReportForm{}).Error; err != nil {
        return err
    }
    return nil
}
func (slf *SalaryReportFormSearch) Find() ([]*SalaryReportForm, int64, error) {
    var (
        records = make([]*SalaryReportForm, 0)
        total   int64
        db      = slf.build()
    )
    if err := db.Count(&total).Error; err != nil {
        return records, total, fmt.Errorf("find count err: %v", err)
    }
    if slf.PageNum*slf.PageSize > 0 {
        db = db.Offset((slf.PageNum - 1) * slf.PageSize).Limit(slf.PageSize)
    }
    if err := db.Find(&records).Error; err != nil {
        return records, total, fmt.Errorf("find records err: %v", err)
    }
    return records, total, nil
}
func (slf *SalaryReportFormSearch) FindNotTotal() ([]*SalaryReportForm, error) {
    var (
        records = make([]*SalaryReportForm, 0)
        db      = slf.build()
    )
    if err := db.Find(&records).Error; err != nil {
        return records, fmt.Errorf("find records err: %v", err)
    }
    return records, nil
}
func (slf *SalaryReportFormSearch) Count() (int64, error) {
    var (
        total int64
        db    = slf.build()
    )
    if err := db.Count(&total).Error; err != nil {
        return total, fmt.Errorf("find count err: %v", err)
    }
    return total, nil
}
models/work_type_manage.go
@@ -8,6 +8,7 @@
)
type (
    //WorkTypeManage 工种管理
    WorkTypeManage struct {
        gorm.Model
        WorkName        string          `json:"workName" gorm:"type:varchar(255);comment:工种名称"`
@@ -22,6 +23,7 @@
        PageNum  int
        PageSize int
        Preload  bool
        Ids      []uint
        Orm      *gorm.DB
    }
)
@@ -54,6 +56,11 @@
    return slf
}
func (slf *WorkTypeManageSearch) SetIds(ids []uint) *WorkTypeManageSearch {
    slf.Ids = ids
    return slf
}
func (slf *WorkTypeManageSearch) build() *gorm.DB {
    var db = slf.Orm.Table(slf.TableName())
@@ -61,6 +68,10 @@
        db = db.Where("id = ?", slf.ID)
    }
    if len(slf.Ids) > 0 {
        db = db.Where("id in (?)", slf.Ids)
    }
    if slf.Preload {
        db = db.Model(WorkTypeManage{}).Preload("SalaryPlans")
    }
models/yield_register_item.go
@@ -20,7 +20,9 @@
    }
    YieldRegisterItemSearch struct {
        YieldRegisterItem
        Orm *gorm.DB
        YieldRegisterIds []uint
        CarNumbers       []int
        Orm              *gorm.DB
    }
)
@@ -42,6 +44,15 @@
    return slf
}
func (slf *YieldRegisterItemSearch) SetYieldRegisterIds(ids []uint) *YieldRegisterItemSearch {
    slf.YieldRegisterIds = ids
    return slf
}
func (slf *YieldRegisterItemSearch) SetCarNumbers(carNumbers []int) *YieldRegisterItemSearch {
    slf.CarNumbers = carNumbers
    return slf
}
func (slf *YieldRegisterItemSearch) build() *gorm.DB {
    db := slf.Orm.Table(slf.TableName())
@@ -49,6 +60,14 @@
        db = db.Where("yield_register_id = ?", slf.YieldRegisterId)
    }
    if len(slf.YieldRegisterIds) > 0 {
        db = db.Where("yield_register_id in (?)", slf.YieldRegisterIds)
    }
    if len(slf.CarNumbers) > 0 {
        db = db.Where("car_number in (?)", slf.CarNumbers)
    }
    return db
}
task/salary_statistics.go
New file
@@ -0,0 +1,227 @@
package task
import (
    "github.com/shopspring/decimal"
    "silkserver/constvar"
    "silkserver/models"
    "silkserver/pkg/logx"
    "silkserver/utils"
    "strings"
    "time"
)
func SalaryStatistics() {
    lastMonthStart, lastMonthEnd := GetLastMonthPeriod()
    month := lastMonthStart.Format("2006-01")
    //查询考勤统计
    startStr := lastMonthStart.Format("2006-01-02")
    endStr := lastMonthEnd.Format("2006-01-02")
    attendances, err := models.NewAttendanceManageSearch().SetMonth(month).FindNotTotal()
    if err != nil {
        logx.Error("SalaryStatistics 查询考勤统计 err: " + err.Error())
        return
    }
    var reportForms []*models.SalaryReportForm
    workTypeIdMap := make(map[uint]uint)
    dataMap := make(map[string]utils.SalaryCalculateData)
    for _, attendance := range attendances {
        var rf models.SalaryReportForm
        var data utils.SalaryCalculateData
        if _, ok := dataMap[attendance.WorkerId]; ok {
            data = dataMap[attendance.WorkerId]
        }
        rf.WorkerId = attendance.WorkerId
        rf.WorkerName = attendance.WorkerName
        rf.WorkTypeId = attendance.WorkTypeId
        rf.Month = month
        rf.Phone = attendance.PhoneNum
        if attendance.WorkTypeId > 0 {
            workTypeIdMap[attendance.WorkTypeId] = attendance.WorkTypeId
        }
        //工作日加班时长
        data.WeekdayOvertimeHours = data.WeekdayOvertimeHours.Add(attendance.OverTimeDuration)
        //出勤天数
        if attendance.Status != constvar.Vacation {
            data.TotalAttendanceDays = data.TotalAttendanceDays + 1
        }
        dataMap[attendance.WorkerId] = data
        reportForms = append(reportForms, &rf)
    }
    workTypeIds := make([]uint, 0)
    for _, v := range workTypeIdMap {
        workTypeIds = append(workTypeIds, v)
    }
    //查询工种的薪资方案和新增类型
    workTypeManages, err := models.NewWorkTypeManageSearch().SetIds(workTypeIds).SetPreload(true).FindNotTotal()
    if err != nil {
        logx.Error("SalaryStatistics 查询工种的薪资方案和新增类型 err: " + err.Error())
        return
    }
    for _, form := range reportForms {
        details := make([]models.SalaryDetails, 0)
        issueSalary := decimal.NewFromInt(0)
        for _, manage := range workTypeManages {
            if form.WorkTypeId == manage.ID {
                data := dataMap[form.WorkerId]
                for _, plan := range manage.SalaryPlans {
                    formula := strings.ReplaceAll(plan.SalaryFormula, ",", "")
                    var detail models.SalaryDetails
                    detail.SalaryTypeId = plan.SalaryTypeId
                    amount := decimal.NewFromInt(0)
                    f := constvar.DailySilkProduction + "*" + constvar.RawSilkUnitPrice
                    if strings.Contains(formula, f) {
                        data, err = GetDailySilkProduction(startStr, endStr, form.WorkerId, data)
                        if err != nil {
                            logx.Error("SalaryStatistics 统计薪资出错 err: " + err.Error())
                        } else {
                            amount, err = utils.CalculateSalary(data, formula)
                            if err != nil {
                                logx.Error("SalaryStatistics 计算薪资出错 err: " + err.Error())
                            }
                        }
                    }
                    detail.Amount = amount
                    issueSalary = issueSalary.Add(amount)
                    details = append(details, detail)
                }
            }
        }
        form.Details = details
        form.IssueSalary = issueSalary
    }
    //插入数据库
    err = models.NewSalaryReportFormSearch().CreateBatch(reportForms)
    if err != nil {
        logx.Error("SalaryStatistics 插入数据库出错 err: " + err.Error())
    }
}
func GetDailySilkProduction(start, end, workerId string, data utils.SalaryCalculateData) (utils.SalaryCalculateData, error) {
    //查询机台管理
    var cars []models.WorkerPosition
    err := models.NewWorkerPositionSearch().Orm.Table("silk_worker_position").Where("worker_id = ? and start_date >= ? and "+
        "end_date <= ?", workerId, start, end).Find(&cars).Error
    if err != nil {
        return data, err
    }
    endCarMap := make(map[int]int)
    groupMap := make(map[int]int)
    workshopMap := make(map[string]string)
    for _, car := range cars {
        endCarMap[car.EndWorkerPosition] = car.EndWorkerPosition
        groupMap[car.WorkshopGroup] = car.WorkshopGroup
        workshopMap[car.Workshop] = car.Workshop
    }
    groups := make([]int, 0)
    workshops := make([]string, 0)
    endCars := make([]int, 0)
    for _, v := range endCarMap {
        endCars = append(endCars, v)
    }
    for _, v := range workshopMap {
        workshops = append(workshops, v)
    }
    for _, v := range groupMap {
        groups = append(groups, v)
    }
    //查询产量登记表
    var yield []models.YieldRegister
    err = models.NewYieldRegisterSearch().Orm.Table("silk_yield_register").Where("workshop_number in (?) and group_number "+
        "in (?) and create_time >= ? and create_time <= ?", workshops, groups, start, end).Find(&yield).Error
    if err != nil {
        return data, err
    }
    yieldRegisterIds := make([]uint, 0)
    for _, register := range yield {
        yieldRegisterIds = append(yieldRegisterIds, register.ID)
    }
    yieldMap := make(map[string]decimal.Decimal)
    items, err := models.NewYieldRegisterItemSearch().SetYieldRegisterIds(yieldRegisterIds).SetCarNumbers(endCars).FindNotTotal()
    if err != nil {
        return data, err
    }
    for _, register := range yield {
        for _, item := range items {
            if register.ID == item.YieldRegisterId {
                yieldMap[register.CreateTime] = item.PeopleYield
            }
        }
    }
    //查询纤度登记表
    var fineness []models.FinenessRegister
    markets := make([]string, 0)
    err = models.NewFinenessRegisterSearch().Orm.Table("silk_fineness_register").Where("workshop in (?) and workshop_group "+
        "in (?) and finish_date >= ? and finish_date <= ?", workshops, groups, start, end).Find(&fineness).Error
    if err != nil {
        return data, err
    }
    finenessIds := make([]uint, 0)
    for _, register := range fineness {
        finenessIds = append(finenessIds, register.ID)
        markets = append(markets, register.Market)
    }
    var checkItems []models.FinenessCheckItem
    err = models.NewFinenessCheckItemSearch().Orm.Table("silk_fineness_check_item").Where("fineness_register_id in (?) and "+
        "position in (?)", finenessIds, endCars).Find(&checkItems).Error
    if err != nil {
        return data, err
    }
    checkMap := make(map[string]string)
    marketMap := make(map[string]string)
    for _, item := range checkItems {
        for _, register := range fineness {
            if item.FinenessRegisterID == register.ID {
                checkMap[register.FinishDate] = item.FinenessGrade
                marketMap[register.FinishDate] = register.Market
                break
            }
        }
    }
    //查询不同庄口下的生丝定价
    find, _, err := models.NewRawSilkPriceStandardSearch().SetMarketNames(markets).Find()
    if err != nil {
        return data, err
    }
    //计算每日工资
    total := decimal.NewFromInt(0)
    for date, amount := range yieldMap {
        grade := checkMap[date]
        market := marketMap[date]
        for _, standard := range find {
            if standard.MarketName == market && standard.RawSilkGrade == grade {
                h := amount.Mul(standard.PayStandard)
                total = total.Add(h)
                break
            }
        }
    }
    data.DailySilkProduction = total
    data.RawSilkUnitPrice = decimal.NewFromInt(1)
    return data, nil
}
// GetLastMonthPeriod 返回上个月的月初时间和月末时间
func GetLastMonthPeriod() (time.Time, time.Time) {
    // 获取当前时间
    now := time.Now()
    // 计算上个月的年份和月份
    lastMonth := now.AddDate(0, -1, 0)
    lastYear, lastMonthNum, _ := lastMonth.Date()
    // 获取上个月的第一天的日期(即上个月月初)
    firstDayOfLastMonth := time.Date(lastYear, lastMonthNum, 1, 0, 0, 0, 0, now.Location())
    // 获取本月第一天的日期(即本月月初)
    firstDayOfThisMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
    // 上个月月末时间即为本月月初减去一秒
    lastDayOfLastMonth := firstDayOfThisMonth.Add(-time.Second)
    return firstDayOfLastMonth, lastDayOfLastMonth
}
utils/salary_calculate.go
New file
@@ -0,0 +1,63 @@
package utils
import (
    "github.com/Knetic/govaluate"
    "github.com/shopspring/decimal"
    "strconv"
    "strings"
)
// 薪资计算数据
type SalaryCalculateData struct {
    DailySilkProduction     decimal.Decimal `json:"dailySilkProduction"`     // 日产丝量
    WasteSilkQuantity       decimal.Decimal `json:"wasteSilkQuantity"`       // 野纤数量
    RawSilkUnitPrice        decimal.Decimal `json:"rawSilkUnitPrice"`        // 生丝单价
    WasteSilkUnitPrice      decimal.Decimal `json:"wasteSilkUnitPrice"`      // 野纤单价
    BucketCount             decimal.Decimal `json:"bucketCount"`             //桶数(日)
    AttendanceDays          int             `json:"attendanceDays"`          // 出勤天数
    GroupAverageMonthlyWage decimal.Decimal `json:"groupAverageMonthlyWage"` //同组挡车工月平均工资
    GroupCarHeadWage        decimal.Decimal `json:"groupCarHeadWage"`        //同组车头工工资
    WeekdayOvertimeHours decimal.Decimal `json:"weekdayOvertimeHours"` // 工作日加班时长
    FullAttendanceAward  int             `json:"FullAttendanceAward"`  // 满勤奖
    WeekendOvertimeHours decimal.Decimal `json:"weekendOvertimeHours"` // 休息日加班时长
    LeaveDays            decimal.Decimal `json:"LeaveDays"`            //请假天数
    ApprenticeDays       decimal.Decimal `json:"apprenticeDays"`       // 带徒天数
    TotalAttendanceDays  int             `json:"totalAttendanceDays"`  // 出勤天数
    Seniority            decimal.Decimal `json:"seniority"`            // 工龄
}
// CalculateSalary 计算工资的函数
func CalculateSalary(date SalaryCalculateData, formula string) (decimal.Decimal, error) {
    // 替换公式中的变量
    formula = strings.ReplaceAll(formula, "日产丝量", date.DailySilkProduction.String())
    formula = strings.ReplaceAll(formula, "野纤数量", date.WasteSilkQuantity.String())
    formula = strings.ReplaceAll(formula, "生丝单价", date.RawSilkUnitPrice.String())
    formula = strings.ReplaceAll(formula, "野纤单价", date.WasteSilkUnitPrice.String())
    formula = strings.ReplaceAll(formula, "桶数(日)", date.BucketCount.String())
    formula = strings.ReplaceAll(formula, "出勤天数", strconv.Itoa(date.AttendanceDays))
    formula = strings.ReplaceAll(formula, "同组挡车工月平均工资", date.GroupAverageMonthlyWage.String())
    formula = strings.ReplaceAll(formula, "同组车头工工资", date.GroupCarHeadWage.String())
    formula = strings.ReplaceAll(formula, "工作日加班时长", date.WeekdayOvertimeHours.String())
    formula = strings.ReplaceAll(formula, "满勤奖", strconv.Itoa(date.FullAttendanceAward))
    formula = strings.ReplaceAll(formula, "休息日加班时长", date.WeekendOvertimeHours.String())
    formula = strings.ReplaceAll(formula, "请假天数", date.LeaveDays.String())
    formula = strings.ReplaceAll(formula, "带徒天数", date.ApprenticeDays.String())
    formula = strings.ReplaceAll(formula, "出勤天数", strconv.Itoa(date.TotalAttendanceDays))
    formula = strings.ReplaceAll(formula, "工龄", date.Seniority.String())
    // 使用 govaluate 库计算表达式
    wage := decimal.NewFromInt(0)
    expression, err := govaluate.NewEvaluableExpression(formula)
    if err != nil {
        return wage, err
    }
    parameters := make(map[string]interface{})
    result, err := expression.Evaluate(parameters)
    if err != nil {
        return wage, err
    }
    wage = decimal.NewFromFloat(result.(float64))
    return wage, nil
}