From 800eefcebe850c1a82662b8e54279c1e2d89d8ff Mon Sep 17 00:00:00 2001 From: Jiang Yong Date: Mon, 4 Sep 2023 19:14:02 +0800 Subject: [PATCH] staff --- cmd/enterprise.go | 9 +++- common/model/staff_salary.go | 3 +- common/weixin/qyweixin_approve.go | 79 +++++++++++++++++++++++++++++++ go.mod | 8 ++-- worker/staff.go | 53 ++++++++++++++++++--- worker/worker.go | 4 +- 6 files changed, 142 insertions(+), 14 deletions(-) diff --git a/cmd/enterprise.go b/cmd/enterprise.go index 1e6cc72..e1ceaea 100644 --- a/cmd/enterprise.go +++ b/cmd/enterprise.go @@ -8,7 +8,7 @@ import ( "enterprise/worker" ) -func main() { +func main1() { config.LoadServerConfig() global.InitGlobal() @@ -19,6 +19,13 @@ func main() { panic(err) } } +func main() { + config.LoadServerConfig() + global.InitGlobal() + //cfg := config.GetConfig() + worker.SyncStaffSalary("") + +} func main2() { config.LoadServerConfig() diff --git a/common/model/staff_salary.go b/common/model/staff_salary.go index bb32df7..b0023a1 100644 --- a/common/model/staff_salary.go +++ b/common/model/staff_salary.go @@ -7,7 +7,8 @@ type StaffSalary struct { BaseSalary float64 RealSalary float64 SocialInsurence float64 - Holiday int + PersonalTax float64 + Holiday float64 CreateTime int64 UpdateTime int64 Extra string diff --git a/common/weixin/qyweixin_approve.go b/common/weixin/qyweixin_approve.go index ce34c6d..aaa4443 100644 --- a/common/weixin/qyweixin_approve.go +++ b/common/weixin/qyweixin_approve.go @@ -5,6 +5,8 @@ import ( butil "enterprise/base/util" "fmt" log "github.com/sirupsen/logrus" + "github.com/smbrave/goutil" + "github.com/spf13/cast" ) type Applyer struct { @@ -25,6 +27,17 @@ type Selector struct { Options []*Option `json:"options"` } +type Vacation struct { + Selector *Selector `json:"selector"` + Attendance struct { + DateRange struct { + NewBegin int64 `json:"new_begin"` + NewEnd int64 `json:"new_end"` + NewDuration int64 `json:"new_duration"` + Type string `json:"type"` + } `json:"date_range"` + } `json:"attendance"` +} type ApplyValue struct { Text string `json:"text"` Selector *Selector `json:"selector"` @@ -37,6 +50,7 @@ type ApplyValue struct { Files []struct { FileId string `json:"file_id"` } `json:"files"` + Vacation *Vacation `json:"vacation"` } type ApplyContent struct { @@ -70,6 +84,39 @@ type QyWeixinApprove struct { QyWeixin } +func (d *ApproveDetail) GetValue(title string) string { + + for _, content := range d.ApplyData.Contents { + key := content.Title[0].Text + if key != title { + continue + } + + var value string + if content.Control == "Selector" { + value = content.Value.Selector.Options[0].Value[0].Text + } else if content.Control == "Text" || content.Control == "Textarea" { + value = content.Value.Text + } else if content.Control == "Date" { + value = content.Value.Date.Timestamp + } else if content.Control == "Money" { + value = content.Value.NewMoney + } else if content.Control == "File" { + value = content.Value.Files[0].FileId + } else if content.Control == "Vacation" { + tp := content.Value.Vacation.Selector.Options[0].Value[0].Text + duration := cast.ToString(content.Value.Vacation.Attendance.DateRange.NewDuration) + value = tp + "," + duration + } + return value + } + return "" +} + +func (d *ApproveDetail) GetUserid() string { + return d.Applyer.Userid +} + func NewQyWeixinApprove(corpId, secret, agent string) *QyWeixinApprove { return &QyWeixinApprove{ QyWeixin: QyWeixin{ @@ -94,3 +141,35 @@ func (q *QyWeixinApprove) GetDetail(spNo string) (*ApproveDetail, error) { } return rsp.Info, nil } + +func (q *QyWeixinApprove) GetList(start, end int64, templateId string) ([]string, error) { + reqUrl := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/oa/getapprovalinfo?access_token=%s", q.GetToken()) + reqParam := make(map[string]interface{}) + reqParam["starttime"] = cast.ToString(start) + reqParam["endtime"] = cast.ToString(end) + reqParam["new_cursor"] = "" + reqParam["size"] = 100 + filters := make([]interface{}, 0) + if templateId != "" { + filters = append(filters, map[string]interface{}{ + "key": "template_id", + "value": templateId, + }) + } + + filters = append(filters, map[string]interface{}{ + "key": "sp_status", + "value": "2", + }) + reqParam["filters"] = filters + rspBody, err := butil.HttpPostJson(reqUrl, nil, []byte(goutil.EncodeJSON(reqParam))) + if err != nil { + log.Errorf("httpPost error :%s", err.Error()) + return nil, err + } + result, err := q.GetResult(rspBody) + if err != nil { + return nil, err + } + return cast.ToStringSlice(result["sp_no_list"]), nil +} diff --git a/go.mod b/go.mod index 0823916..5e01b0b 100644 --- a/go.mod +++ b/go.mod @@ -4,18 +4,20 @@ go 1.18 require ( github.com/ArtisanCloud/PowerWeChat/v3 v3.0.56 + github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a github.com/gin-gonic/gin v1.9.1 github.com/go-co-op/gocron v1.31.0 github.com/gogap/errors v0.0.0-20210818113853-edfbba0ddea9 + github.com/gomodule/redigo v1.8.1 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible github.com/mitchellh/mapstructure v1.5.0 github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 - github.com/silenceper/wechat v1.2.6 github.com/sirupsen/logrus v1.9.3 github.com/smbrave/goutil v0.0.0-20230602040814-2643c72c2849 github.com/spf13/cast v1.5.1 github.com/spf13/viper v1.16.0 github.com/wechatpay-apiv3/wechatpay-go v0.2.17 + golang.org/x/crypto v0.9.0 gorm.io/driver/mysql v1.5.1 gorm.io/gorm v1.25.2 ) @@ -23,13 +25,11 @@ require ( require ( github.com/ArtisanCloud/PowerLibs/v3 v3.0.12 // indirect github.com/ArtisanCloud/PowerSocialite/v3 v3.0.6 // indirect - github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect - github.com/fatih/structs v1.1.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -39,7 +39,6 @@ require ( github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gogap/stack v0.0.0-20150131034635-fef68dddd4f8 // indirect - github.com/gomodule/redigo v1.8.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect @@ -67,7 +66,6 @@ require ( go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.21.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.9.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect diff --git a/worker/staff.go b/worker/staff.go index cf38b28..3bd449e 100644 --- a/worker/staff.go +++ b/worker/staff.go @@ -59,7 +59,11 @@ func SyncStaffInfo() { } } -func CalcStaffSalary(month string) { +func SyncStaffSalary(month string) { + if month == "" { + month = time.Now().AddDate(0, -1, 0).Format("2006-01") + } + month = strings.ReplaceAll(month, "-", "") //cfg := config.GetConfig() //hrAssiant := weixin.NewQyWeixinHR(cfg.QyWeixin.Corpid, cfg.QyWeixin.HrSecret, cfg.QyWeixin.HrSecret) @@ -68,7 +72,11 @@ func CalcStaffSalary(month string) { log.Errorf("query staff db error :%s", err.Error()) return } - month = strings.ReplaceAll(month, "-", "") + holidays, err := loadHoliday(month) + if err != nil { + log.Errorf("loadHoliday error :%s", err.Error()) + return + } monthTime, _ := time.ParseInLocation("200601", month, time.Local) startDate := cast.ToInt(monthTime.Format("20060102")) endDate := cast.ToInt(monthTime.AddDate(0, 1, -1).Format("20060102")) @@ -94,9 +102,7 @@ func CalcStaffSalary(month string) { discount = 0.8 } socialInsurence := cast.ToFloat64(config.Get(model.StaffSalarySocialInsurence)) - if endDate%100 > 15 { // 15号以后的员工不缴社保 - socialInsurence = 0 - } + extra := make(map[string]interface{}) salary.BaseSalary = cast.ToFloat64(staff.Salary) @@ -116,6 +122,9 @@ func CalcStaffSalary(month string) { if officialDate/100 == startDate/100 { isOfficialMonth = true } + if entryDate%100 > 15 && isEntryMonth { // 15号以后的员工不缴社保 + socialInsurence = 0 + } if isEntryMonth { expDays = endDate - entryDate + 1 @@ -130,10 +139,11 @@ func CalcStaffSalary(month string) { officialDays = endDate - startDate + 1 expDays = 0 } + holiday := butil.FloatCut(holidays[staff.Username]) expSalary := cast.ToFloat64(staff.Salary) * discount / float64(endDate-startDate+1) officalSalary := cast.ToFloat64(staff.Salary) / float64(endDate-startDate+1) - realSalary := expSalary*float64(expDays) + officalSalary*float64(officialDays) - socialInsurence + realSalary := expSalary*float64(expDays) + officalSalary*float64(officialDays) - holiday*officalSalary extra["discount"] = discount extra["socialInsurence"] = socialInsurence @@ -152,6 +162,7 @@ func CalcStaffSalary(month string) { salary.RealSalary = butil.FloatCut(realSalary) salary.SocialInsurence = socialInsurence + salary.Holiday = holiday salary.Extra = goutil.EncodeJSONIndent(extra) if salary.Id == 0 { _, err = dao.NewStaffSalaryDao().Create(salary) @@ -164,3 +175,33 @@ func CalcStaffSalary(month string) { } } + +func loadHoliday(month string) (map[string]float64, error) { + cfg := config.GetConfig().QyWeixin + approve := weixin.NewQyWeixinApprove(cfg.Corpid, cfg.ApproveSecret, cfg.ApproveAgent) + startTime, _ := time.ParseInLocation("200601", month, time.Local) + endTime := startTime.AddDate(0, 1, 0) + spNos, err := approve.GetList(startTime.Unix(), endTime.Unix()-1, "3WLJF6naF5jhnXvwisuPmE85wVMYcy1S1ZvYibkw") + if err != nil { + log.Errorf("approve getlist error :%s", err.Error()) + return nil, err + } + result := make(map[string]float64) + for _, spNo := range spNos { + detail, err := approve.GetDetail(spNo) + if err != nil { + log.Errorf("approve GetDetail error :%s", err.Error()) + return nil, err + } + userId := detail.GetUserid() + holidayType := detail.GetValue("请假类型") + fields := strings.SplitN(holidayType, ",", 2) + hours := float64(cast.ToInt64(fields[1])) / float64(3600*8) + if v, ok := result[userId]; ok { + result[userId] = v + hours + } else { + result[userId] = hours + } + } + return result, nil +} diff --git a/worker/worker.go b/worker/worker.go index ce39cb7..79d70c2 100644 --- a/worker/worker.go +++ b/worker/worker.go @@ -23,7 +23,9 @@ func Init() error { cron.Every(1).Day().At("03:00").Do(func() { go SyncStaffInfo() }) - + cron.Every(1).Month(1, 2, 3, 4, 5).At("02:00").Do(func() { + go SyncStaffSalary("") + }) cron.StartAsync() return nil }