This commit is contained in:
jiangyong 2024-01-07 17:17:33 +08:00
parent 0cc9569692
commit a868f820bb
8 changed files with 155 additions and 134 deletions

View File

@ -3,7 +3,6 @@ package main
import ( import (
"enterprise/common/config" "enterprise/common/config"
"enterprise/common/global" "enterprise/common/global"
"enterprise/common/weixin"
"enterprise/server" "enterprise/server"
"enterprise/worker" "enterprise/worker"
) )
@ -20,25 +19,9 @@ func main() {
panic(err) panic(err)
} }
} }
func main3() {
config.LoadServerConfig()
global.InitGlobal()
//cfg := config.GetConfig()
worker.SyncStaffInfo()
worker.SyncStaffSalary("")
}
func main2() { func main2() {
config.LoadServerConfig() config.LoadServerConfig()
//global.InitGlobal() global.InitGlobal()
//cfg := config.GetConfig()
pay := weixin.NewQyPay()
if err := pay.PayRedMoney(&weixin.RedMoneyReq{
TotalAmount: 200,
Title: "加班补贴",
Userid: "jiangyong",
}); err != nil {
panic(err)
}
} }

View File

@ -4,6 +4,7 @@ type Checkin struct {
Id int64 Id int64
Username string Username string
Day string Day string
Month string
Exception string Exception string
Rawdata string Rawdata string
StartTime int64 StartTime int64

View File

@ -9,12 +9,12 @@ import (
"github.com/smbrave/goutil" "github.com/smbrave/goutil"
"github.com/spf13/cast" "github.com/spf13/cast"
"gorm.io/gorm/utils" "gorm.io/gorm/utils"
"math"
"strings"
"time" "time"
) )
type UserCheckIn struct { type UserCheckIn struct {
Day string
Month string
UserId string UserId string
Exception string Exception string
Rawdata string Rawdata string
@ -22,6 +22,11 @@ type UserCheckIn struct {
EndTime int64 EndTime int64
} }
func (u *UserCheckIn) String() string {
return fmt.Sprintf("[%s][%s][%s~%s][%s]", u.UserId, u.Day,
goutil.TimeToDateTime(u.StartTime), goutil.TimeToDateTime(u.EndTime), u.Exception)
}
type QyWeixinCheckin struct { type QyWeixinCheckin struct {
QyWeixin QyWeixin
} }
@ -56,7 +61,7 @@ func (q *QyWeixinCheckin) GetCheckinEmployee(groupIds []string) ([]string, error
groups := cast.ToSlice(result["group"]) groups := cast.ToSlice(result["group"])
for _, group := range groups { for _, group := range groups {
g := cast.ToStringMap(group) g := cast.ToStringMap(group)
if !utils.Contains(groupIds, cast.ToString(g["groupid"])) { if len(groupIds) != 0 && !utils.Contains(groupIds, cast.ToString(g["groupid"])) {
continue continue
} }
ranges := cast.ToStringMap(g["range"]) ranges := cast.ToStringMap(g["range"])
@ -66,15 +71,16 @@ func (q *QyWeixinCheckin) GetCheckinEmployee(groupIds []string) ([]string, error
return resultUser, nil return resultUser, nil
} }
func (q *QyWeixinCheckin) GetCheckinData(day, userId string) (*UserCheckIn, error) { func (q *QyWeixinCheckin) GetCheckinData(startDay, endDay string, userIds []string) ([]*UserCheckIn, error) {
dayTime, _ := time.ParseInLocation("2006-01-02", day, time.Local) dayTime, _ := time.ParseInLocation("2006-01-02", startDay, time.Local)
endTime, _ := time.ParseInLocation("2006-01-02", endDay, time.Local)
reqData := make(map[string]interface{}) reqData := make(map[string]interface{})
reqData["opencheckindatatype"] = 1 reqData["opencheckindatatype"] = 1
reqData["starttime"] = dayTime.Unix() reqData["starttime"] = dayTime.Unix()
reqData["endtime"] = dayTime.Unix() + 86400 reqData["endtime"] = endTime.Unix() + 86400
reqData["useridlist"] = []string{userId} reqData["useridlist"] = userIds
reqUrl := fmt.Sprintf("%s?access_token=%s", urlGetCheckinData, q.GetToken()) reqUrl := fmt.Sprintf("%s?access_token=%s", urlGetCheckinData, q.GetToken())
rspBody, err := butil.HttpPostJson(reqUrl, nil, []byte(goutil.EncodeJSON(reqData))) rspBody, err := butil.HttpPostJson(reqUrl, nil, []byte(goutil.EncodeJSON(reqData)))
if err != nil { if err != nil {
@ -90,39 +96,50 @@ func (q *QyWeixinCheckin) GetCheckinData(day, userId string) (*UserCheckIn, erro
return nil, errors.New(string(rspBody)) return nil, errors.New(string(rspBody))
} }
checkindatas := cast.ToSlice(result["checkindata"]) datas := cast.ToSlice(result["checkindata"])
userData := new(UserCheckIn) checkData := make(map[string]*UserCheckIn)
userData.UserId = userId for _, dat := range datas {
exception := make([]string, 0) c := cast.ToStringMap(dat)
isException := false
startTime := int64(math.MaxInt64)
endTime := int64(0)
for _, checkdata := range checkindatas {
c := cast.ToStringMap(checkdata)
exceptionType := cast.ToString(c["exception_type"]) exceptionType := cast.ToString(c["exception_type"])
checkinType := cast.ToString(c["checkin_type"])
userid := cast.ToString(c["userid"])
checkinTime := cast.ToInt64(c["checkin_time"]) checkinTime := cast.ToInt64(c["checkin_time"])
schCheckinTime := cast.ToInt64(c["sch_checkin_time"])
if schCheckinTime == 0 {
schCheckinTime = checkinTime
}
checkDay := time.Unix(schCheckinTime, 0).Format("2006-01-02")
checkMonth := time.Unix(schCheckinTime, 0).Format("200601")
key := fmt.Sprintf("%s_%s", userid, checkDay)
var userData *UserCheckIn = nil
var ok bool
if userData, ok = checkData[key]; !ok {
userData = new(UserCheckIn)
userData.UserId = userid
userData.Day = checkDay
userData.Month = checkMonth
checkData[key] = userData
}
if exceptionType != "" { if exceptionType != "" {
isException = true userData.Exception += goutil.If(userData.Exception != "", ",", "")
userData.Exception += checkinType + ":" + exceptionType
} }
userData.Rawdata = goutil.If(userData.Rawdata == "", "", "\n") + goutil.EncodeJSON(dat)
if checkinType == "上班打卡" {
userData.StartTime = goutil.If(userData.StartTime == 0 || checkinTime < userData.StartTime, checkinTime, userData.StartTime)
} else if checkinType == "下班打卡" {
userData.EndTime = goutil.If(checkinTime > userData.EndTime, checkinTime, userData.EndTime)
} else {
log.Errorf("不支持的打卡类型:%s %s", checkinType, goutil.EncodeJSON(dat))
}
}
exception = append(exception, exceptionType) userDatas := make([]*UserCheckIn, 0)
if checkinTime < startTime { for _, v := range checkData {
startTime = checkinTime if v.StartTime > v.EndTime {
} log.Errorf("user[%s][%s] checkin time error[%s~%s]", v.UserId, v.Day, goutil.TimeToDateTime(v.StartTime), goutil.TimeToDateTime(v.EndTime))
if checkinTime > endTime {
endTime = checkinTime
} }
userDatas = append(userDatas, v)
} }
if startTime != int64(math.MaxInt64) { return userDatas, nil
userData.StartTime = startTime
}
userData.EndTime = endTime
userData.Rawdata = goutil.EncodeJSON(checkindatas)
if isException {
userData.Exception = strings.Join(exception, ",")
}
if userData.EndTime == 0 && userData.StartTime == 0 {
return nil, nil
}
return userData, nil
} }

View File

@ -4,8 +4,8 @@ address = "0.0.0.0:9283"
log_level = 6 log_level = 6
[mysql] [mysql]
host = "100.100.199.74" host = "14.22.113.49"
port = 3307 port = 9305
user = "root" user = "root"
pass = "ZW5aaGVuMIIBIj" pass = "ZW5aaGVuMIIBIj"
db = "enterprise" db = "enterprise"
@ -27,6 +27,7 @@ checkin_agent = "3010011"
checkin_secret = "6ljYNGt4DonZLmr9SCtgkTlOvtqmsOchBrTWwGl_GpU" checkin_secret = "6ljYNGt4DonZLmr9SCtgkTlOvtqmsOchBrTWwGl_GpU"
checkin_group = "1,2" checkin_group = "1,2"
checkin_pay_thresold = 11 checkin_pay_thresold = 11
checkin_onduty_pay_day = ""
pay_secret = "JCGsxntR4E7wrEEQvWGr8_wdKtRlw48n-W6zd8lbwc4" pay_secret = "JCGsxntR4E7wrEEQvWGr8_wdKtRlw48n-W6zd8lbwc4"
pay_agent = "3010046" pay_agent = "3010046"

View File

@ -35,11 +35,11 @@ func (s *Staff) Salary(ctx *gin.Context) {
} }
func (s *Staff) SyncStaffInfo(ctx *gin.Context) { func (s *Staff) SyncStaffInfo(ctx *gin.Context) {
go worker.SyncStaffInfo() go new(worker.Staff).SyncStaffInfo()
ctx.JSON(http.StatusOK, session.NewRspOk()) ctx.JSON(http.StatusOK, session.NewRspOk())
} }
func (s *Staff) SyncStaffSalary(ctx *gin.Context) { func (s *Staff) SyncStaffSalary(ctx *gin.Context) {
go worker.SyncStaffSalary("") go new(worker.Staff).SyncStaffSalary("")
ctx.JSON(http.StatusOK, session.NewRspOk()) ctx.JSON(http.StatusOK, session.NewRspOk())
} }

View File

@ -6,71 +6,91 @@ import (
"enterprise/common/model" "enterprise/common/model"
"enterprise/common/weixin" "enterprise/common/weixin"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"strings" "github.com/smbrave/goutil"
"time" "time"
) )
func SyncCheckin(day string) error { type CheckIn struct {
}
func (c *CheckIn) SyncCheckinMonth(month string) error {
if month == "" {
month = time.Now().AddDate(0, -1, 0).Format("200601")
}
cfg := config.GetConfig() cfg := config.GetConfig()
startTime, _ := time.ParseInLocation("20060102", month+"01", time.Local)
endDay := startTime.AddDate(0, 1, -1).Format("2006-01-02")
startDay := startTime.Format("2006-01-02")
qyw := weixin.NewQyWeixinCheckin(cfg.QyWeixin.Corpid, cfg.QyWeixin.CheckinSecret, cfg.QyWeixin.CheckinAgent) qyw := weixin.NewQyWeixinCheckin(cfg.QyWeixin.Corpid, cfg.QyWeixin.CheckinSecret, cfg.QyWeixin.CheckinAgent)
users, err := qyw.GetCheckinEmployee(strings.Split(cfg.QyWeixin.CheckinGroup, ",")) users, err := qyw.GetCheckinEmployee(nil)
if err != nil { if err != nil {
log.Errorf("GetCheckinEmployee error :%s", err.Error())
return err return err
} }
checkinDao := dao.NewCheckinDao() userDatas, err := qyw.GetCheckinData(startDay, endDay, users)
for _, user := range users { if err != nil {
isNew := false log.Errorf("GetCheckinData[%s-%s]%s error :%s", startDay, endDay, goutil.EncodeJSON(users), err.Error())
isUpdate := false return err
checkin, err := checkinDao.GetByDay(user, day) }
if err != nil { for _, user := range userDatas {
log.Errorf("db error :%s", err.Error()) c.saveToDB(user)
continue }
} return nil
if checkin == nil { }
checkin = new(model.Checkin) func (c *CheckIn) SyncCheckinDay(day string) {
checkin.Day = day cfg := config.GetConfig()
checkin.Username = user qyw := weixin.NewQyWeixinCheckin(cfg.QyWeixin.Corpid, cfg.QyWeixin.CheckinSecret, cfg.QyWeixin.CheckinAgent)
isNew = true if day == "" {
} day = time.Now().AddDate(0, 0, -1).Format("2006-01-02")
}
users, err := qyw.GetCheckinEmployee(nil)
if err != nil {
log.Errorf("GetCheckinEmployee error :%s", err.Error())
return
}
realCheckin, err := qyw.GetCheckinData(day, user) userDatas, err := qyw.GetCheckinData(day, day, users)
if err != nil { if err != nil {
log.Errorf("qyweixin get checkin error :%s", err.Error()) log.Errorf("GetCheckinData[%s-%s]%s error :%s", day, day, goutil.EncodeJSON(users), err.Error())
continue return
} }
if realCheckin == nil {
continue for _, user := range userDatas {
} c.saveToDB(user)
if realCheckin.StartTime != 0 && realCheckin.StartTime != checkin.StartTime { }
isUpdate = true return
checkin.StartTime = realCheckin.StartTime }
} func (c *CheckIn) saveToDB(user *weixin.UserCheckIn) error {
if realCheckin.EndTime != 0 && realCheckin.EndTime != checkin.EndTime { checkin, err := dao.NewCheckinDao().GetByDay(user.UserId, user.Day)
isUpdate = true if err != nil {
checkin.EndTime = realCheckin.EndTime log.Errorf("db error :%s", err.Error())
} return err
if realCheckin.Exception != "" && realCheckin.Exception != checkin.Exception { }
checkin.Exception = realCheckin.Exception isNew := false
isUpdate = true if checkin == nil {
} checkin = new(model.Checkin)
checkin.Rawdata = realCheckin.Rawdata checkin.Day = user.Day
if isNew { checkin.Month = user.Month
_, err = checkinDao.Create(checkin) checkin.Username = user.UserId
} else { isNew = true
err = checkinDao.Update(checkin) } else {
} checkin.Exception = user.Exception
if err != nil { checkin.StartTime = user.StartTime
log.Errorf("db error :%s", err.Error()) checkin.EndTime = user.EndTime
continue checkin.Month = user.Month
} }
if isNew {
go NotifyCheckinOnDuty(checkin) if isNew {
} _, err = dao.NewCheckinDao().Create(checkin)
if isUpdate { } else {
go NotifyCheckinOffDuty(checkin) err = dao.NewCheckinDao().Update(checkin)
} }
time.Sleep(300 * time.Second) if err != nil {
log.Errorf("create/update db error :%s", err.Error())
return err
} }
return nil return nil

View File

@ -15,7 +15,10 @@ import (
"time" "time"
) )
func SendStaffSalaryBill(month string) { type Staff struct {
}
func (s *Staff) SendStaffSalaryBill(month string) {
staffSalarys, err := dao.NewStaffSalaryDao().Query(month) staffSalarys, err := dao.NewStaffSalaryDao().Query(month)
if err != nil { if err != nil {
log.Errorf("db error :%s", err.Error()) log.Errorf("db error :%s", err.Error())
@ -42,7 +45,7 @@ func SendStaffSalaryBill(month string) {
} }
} }
func SyncStaffInfo() { func (s *Staff) SyncStaffInfo() {
cfg := config.GetConfig() cfg := config.GetConfig()
hrAssiant := weixin.NewQyWeixinHR(cfg.QyWeixin.Corpid, cfg.QyWeixin.HrSecret, cfg.QyWeixin.HrSecret) hrAssiant := weixin.NewQyWeixinHR(cfg.QyWeixin.Corpid, cfg.QyWeixin.HrSecret, cfg.QyWeixin.HrSecret)
@ -88,7 +91,7 @@ func SyncStaffInfo() {
} }
} }
func SyncStaffSalary(month string) { func (s *Staff) SyncStaffSalary(month string) {
if month == "" { if month == "" {
month = time.Now().AddDate(0, -1, 0).Format("2006-01") month = time.Now().AddDate(0, -1, 0).Format("2006-01")
} }
@ -101,7 +104,7 @@ func SyncStaffSalary(month string) {
log.Errorf("query staff db error :%s", err.Error()) log.Errorf("query staff db error :%s", err.Error())
return return
} }
holidays, err := loadHoliday(month) holidays, err := s.loadHoliday(month)
if err != nil { if err != nil {
log.Errorf("loadHoliday error :%s", err.Error()) log.Errorf("loadHoliday error :%s", err.Error())
return return
@ -205,7 +208,7 @@ func SyncStaffSalary(month string) {
} }
func loadHoliday(month string) (map[string]float64, error) { func (s *Staff) loadHoliday(month string) (map[string]float64, error) {
cfg := config.GetConfig().QyWeixin cfg := config.GetConfig().QyWeixin
approve := weixin.NewQyWeixinApprove(cfg.Corpid, cfg.ApproveSecret, cfg.ApproveAgent) approve := weixin.NewQyWeixinApprove(cfg.Corpid, cfg.ApproveSecret, cfg.ApproveAgent)
startTime, _ := time.ParseInLocation("200601", month, time.Local) startTime, _ := time.ParseInLocation("200601", month, time.Local)

View File

@ -5,34 +5,30 @@ import (
"time" "time"
) )
func Init1() error {
for i := 0; i < 120; i++ {
day := time.Now().AddDate(0, 0, -1-i).Format("2006-01-02")
SyncCheckin(day)
}
return nil
}
func Init() error { func Init() error {
timezone, _ := time.LoadLocation("Asia/Shanghai") timezone, _ := time.LoadLocation("Asia/Shanghai")
cron := gocron.NewScheduler(timezone) cron := gocron.NewScheduler(timezone)
cron.Every(1).Hour().Do(func() { staff := new(Staff)
go SyncCheckin(time.Now().Format("2006-01-02")) checkIn := new(CheckIn)
})
// 每天同步企业人事信息 // 每天同步企业人事信息
cron.Every(1).Day().At("01:00").Do(func() { cron.Every(1).Day().At("01:00").Do(func() {
go SyncStaffInfo() go staff.SyncStaffInfo()
})
//同步每日考勤数据
cron.Every(1).Day().At("04:00").Do(func() {
go checkIn.SyncCheckinDay("")
}) })
// 1-10号计算工资信息 // 1-10号计算工资信息
cron.Every(1).Month(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).At("02:00").Do(func() { cron.Every(1).Month(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).At("04:30").Do(func() {
go SyncStaffSalary("") go staff.SyncStaffSalary("")
}) })
//10号晚上8点发送工资单 //10号晚上8点发送工资单
cron.Every(1).Month(10).At("22:00").Do(func() { cron.Every(1).Month(10).At("20:00").Do(func() {
go SendStaffSalaryBill(time.Now().AddDate(0, -1, 0).Format("200601")) go staff.SendStaffSalaryBill(time.Now().AddDate(0, -1, 0).Format("200601"))
}) })
cron.StartAsync() cron.StartAsync()
return nil return nil