This commit is contained in:
Jiang Yong 2023-09-04 19:14:02 +08:00
parent b6e5112bb6
commit 800eefcebe
6 changed files with 142 additions and 14 deletions

View File

@ -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()

View File

@ -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

View File

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

8
go.mod
View File

@ -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

View File

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

View File

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