From 76a84d89d63041232c646ca28c59239dd00f7fc5 Mon Sep 17 00:00:00 2001 From: liujiandao <274878379@qq.com> Date: 星期二, 30 四月 2024 09:58:46 +0800 Subject: [PATCH] 薪资计算 --- task/salary_statistics.go | 227 ++++++++++++++++ controllers/response/report_forms_response.go | 8 models/mini_dict.go | 20 + controllers/report_forms_controller.go | 32 ++ controllers/request/worker_request.go | 1 controllers/salary_plan_controller.go | 70 ++++ go.mod | 3 utils/salary_calculate.go | 63 ++++ models/raw_silk_price_standard.go | 18 + constvar/const.go | 18 + models/salary_plan.go | 8 controllers/attendance_controller.go | 1 controllers/request/report_forms_request.go | 6 models/salary_report_form.go | 163 +++++++++++ go.sum | 2 models/work_type_manage.go | 11 models/salary_details.go | 158 +++++++++++ models/yield_register_item.go | 21 + models/attendance_manage.go | 1 19 files changed, 813 insertions(+), 18 deletions(-) diff --git a/constvar/const.go b/constvar/const.go index 018497d..b89e679 100644 --- a/constvar/const.go +++ b/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 = "宸ラ緞" +) diff --git a/controllers/attendance_controller.go b/controllers/attendance_controller.go index 7d0d3f1..984b09a 100644 --- a/controllers/attendance_controller.go +++ b/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 } } diff --git a/controllers/report_forms_controller.go b/controllers/report_forms_controller.go new file mode 100644 index 0000000..b00be87 --- /dev/null +++ b/controllers/report_forms_controller.go @@ -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(¶ms) + //if err != nil { + // util.ResponseFormat(c, code.RequestParamError, "鍙傛暟瑙f瀽澶辫触锛屾暟鎹被鍨嬮敊璇�") + // return + //} + //workers, err := models.NewWorkerSearch().SetPage(params.Page, params.PageSize).FindNotTotal() + //if err != nil { + // util.ResponseFormat(c, code.RequestParamError, err) + // return + //} + +} diff --git a/controllers/request/report_forms_request.go b/controllers/request/report_forms_request.go new file mode 100644 index 0000000..6ce2f3d --- /dev/null +++ b/controllers/request/report_forms_request.go @@ -0,0 +1,6 @@ +package request + +type SalaryReportForms struct { + PageInfo + Month string `json:"month"` +} diff --git a/controllers/request/worker_request.go b/controllers/request/worker_request.go index 1e15736..3ee1f39 100644 --- a/controllers/request/worker_request.go +++ b/controllers/request/worker_request.go @@ -23,6 +23,7 @@ } type SalaryTypeValue struct { + Id uint `json:"id"` Name string `json:"name"` //鍚嶇О IsDefault bool `json:"isDefault"` //鏄惁鍙紪杈� } diff --git a/controllers/response/report_forms_response.go b/controllers/response/report_forms_response.go new file mode 100644 index 0000000..598df6e --- /dev/null +++ b/controllers/response/report_forms_response.go @@ -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"` +} diff --git a/controllers/salary_plan_controller.go b/controllers/salary_plan_controller.go index fb8d9aa..02109c9 100644 --- a/controllers/salary_plan_controller.go +++ b/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 { diff --git a/go.mod b/go.mod index 9990c00..0b283cf 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index 61b0da4..f0f9548 100644 --- a/go.sum +++ b/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= diff --git a/models/attendance_manage.go b/models/attendance_manage.go index 26996cc..412bf42 100644 --- a/models/attendance_manage.go +++ b/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 diff --git a/models/mini_dict.go b/models/mini_dict.go index 729307e..8941a78 100644 --- a/models/mini_dict.go +++ b/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() diff --git a/models/raw_silk_price_standard.go b/models/raw_silk_price_standard.go index 05348ab..fea5114 100644 --- a/models/raw_silk_price_standard.go +++ b/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 } diff --git a/models/salary_details.go b/models/salary_details.go new file mode 100644 index 0000000..eec1e11 --- /dev/null +++ b/models/salary_details.go @@ -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 +} diff --git a/models/salary_plan.go b/models/salary_plan.go index 1c326ec..55e84d6 100644 --- a/models/salary_plan.go +++ b/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 diff --git a/models/salary_report_form.go b/models/salary_report_form.go new file mode 100644 index 0000000..67aa59f --- /dev/null +++ b/models/salary_report_form.go @@ -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 +} diff --git a/models/work_type_manage.go b/models/work_type_manage.go index e19ce79..d937a25 100644 --- a/models/work_type_manage.go +++ b/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") } diff --git a/models/yield_register_item.go b/models/yield_register_item.go index e9a643a..92720c5 100644 --- a/models/yield_register_item.go +++ b/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 } diff --git a/task/salary_statistics.go b/task/salary_statistics.go new file mode 100644 index 0000000..07e1a1e --- /dev/null +++ b/task/salary_statistics.go @@ -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 +} diff --git a/utils/salary_calculate.go b/utils/salary_calculate.go new file mode 100644 index 0000000..b5c4618 --- /dev/null +++ b/utils/salary_calculate.go @@ -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 +} -- Gitblit v1.8.0