hr assiant

This commit is contained in:
jiangyong27 2023-08-31 22:20:40 +08:00
parent 4a454e1275
commit 8cd07e9033
14 changed files with 798 additions and 21 deletions

View File

@ -12,9 +12,10 @@ func main() {
config.LoadServerConfig()
global.InitGlobal()
if err := worker.Init(); err != nil {
panic(err)
}
worker.SyncStaffInfo()
//if err := worker.Init(); err != nil {
// panic(err)
//}
if err := server.Start(); err != nil {
panic(err)
}

View File

@ -41,7 +41,6 @@ type QyWeixin struct {
CheckinAgent string `toml:"checkin_agent"`
CheckinSecret string `toml:"checkin_secret"`
CheckinGroup string `toml:"checkin_group"`
CheckinPayTitle string `toml:"checkin_pay_title"`
CheckinPayThresold float64 `toml:"checkin_pay_thresold"`
EnterpriseAgent string `toml:"enterprise_agent"`

84
common/dao/staff_info.go Normal file
View File

@ -0,0 +1,84 @@
package dao
import (
"enterprise/common/model"
"gorm.io/gorm"
"time"
)
type StaffInfoDao struct {
}
func NewStaffInfoDao() *StaffInfoDao {
return &StaffInfoDao{}
}
func (d *StaffInfoDao) TableName() string {
return "staff_info"
}
func (d *StaffInfoDao) Create(o *model.StaffInfo) (int64, error) {
o.CreateTime = time.Now().Unix()
res := GetDB().Table(d.TableName()).Create(o)
return o.Id, res.Error
}
func (d *StaffInfoDao) Update(o *model.StaffInfo) error {
o.UpdateTime = time.Now().Unix()
tx := GetDB().Table(d.TableName())
res := tx.Save(o)
return res.Error
}
func (d *StaffInfoDao) Delete(id int64) error {
res := GetDB().Table(d.TableName()).Delete(&model.StaffInfo{}, id)
return res.Error
}
func (d *StaffInfoDao) Get(id int64) (*model.StaffInfo, error) {
var u model.StaffInfo
tx := GetDB().Table(d.TableName())
tx = tx.Where("id = ?", id)
res := tx.First(&u)
if res.Error == gorm.ErrRecordNotFound {
return nil, nil
}
if res.Error != nil {
return nil, res.Error
}
return &u, nil
}
func (d *StaffInfoDao) GetByUsername(username string) (*model.StaffInfo, error) {
var u model.StaffInfo
tx := GetDB().Table(d.TableName())
tx = tx.Where("username = ?", username)
res := tx.First(&u)
if res.Error == gorm.ErrRecordNotFound {
return nil, nil
}
if res.Error != nil {
return nil, res.Error
}
return &u, nil
}
func (d *StaffInfoDao) Query(status int) ([]*model.StaffInfo, error) {
var u []*model.StaffInfo
tx := GetDB().Table(d.TableName())
if status != 0 {
tx = tx.Where("status = ?", status)
}
res := tx.Find(&u)
if res.Error == gorm.ErrRecordNotFound {
return nil, nil
}
if res.Error != nil {
return nil, res.Error
}
return u, nil
}

View File

@ -64,3 +64,22 @@ func (d *UserConfigDao) GetByUsername(username string) (*model.UserConfig, error
}
return &u, nil
}
func (d *UserConfigDao) Query(status int) ([]*model.UserConfig, error) {
var u []*model.UserConfig
tx := GetDB().Table(d.TableName())
if status != 0 {
tx = tx.Where("status = ?", status)
}
res := tx.Find(&u)
if res.Error == gorm.ErrRecordNotFound {
return nil, nil
}
if res.Error != nil {
return nil, res.Error
}
return u, nil
}

View File

@ -0,0 +1,22 @@
package model
var (
StaffInfoStatusNormal = 1
StaffInfoStatusDisable = 2
)
type StaffInfo struct {
Id int64
Username string
Realname string
Phone string
Idno string
Salary string
EntryDate string
OfficialDate string
BirthDate string
BankName string
BankCard string
CreateTime int64
UpdateTime int64
}

View File

@ -8,11 +8,16 @@ var (
CheckinOndutyMoney = "checkin.onduty.money"
CheckinOffdutyMoney = "checkin.offduty.money"
)
var (
UserConfigStatusNormal = 1
UserConfigStatusDisable = 2
)
type UserConfig struct {
Id int64
Username string
Config string
Status int
CreateTime int64
UpdateTime int64
}

View File

@ -3,7 +3,6 @@ package weixin
import (
"encoding/json"
butil "enterprise/base/util"
"errors"
"fmt"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
@ -15,6 +14,7 @@ var (
urlGetCheckinRlue = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcorpcheckinoption"
urlGetCheckinData = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckindata"
urlConvertOpenid = "https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_openid"
urlGetUser = "https://qyapi.weixin.qq.com/cgi-bin/user/get"
)
type QyWeixin struct {
@ -25,6 +25,11 @@ type QyWeixin struct {
tokenExpire int64
}
type UserInfo struct {
UserId string
RealName string
}
func NewQyWeixin(corpId, secret, agent string) *QyWeixin {
return &QyWeixin{
CorpId: corpId,
@ -41,6 +46,19 @@ func (q *QyWeixin) GetToken() string {
return q.Token
}
func (q *QyWeixin) GetResult(rspBody []byte) (map[string]interface{}, error) {
result := make(map[string]interface{})
if err := json.Unmarshal(rspBody, &result); err != nil {
log.Errorf("result[%s] error :%s", string(rspBody), err.Error())
return nil, err
}
if cast.ToInt(result["errcode"]) != 0 {
log.Errorf("result[%s] error ", string(rspBody))
return nil, fmt.Errorf("%d:%s", cast.ToInt(result["errcode"]), cast.ToString(result["errmsg"]))
}
return result, nil
}
func (q *QyWeixin) GetOpenid(userid string) (string, error) {
if err := q.refreshToken(); err != nil {
return "", err
@ -51,18 +69,36 @@ func (q *QyWeixin) GetOpenid(userid string) (string, error) {
log.Errorf("httpPost url[%s] error :%s", reqUrl, err.Error())
return "", err
}
result := make(map[string]interface{})
if err := json.Unmarshal(rspBody, &result); err != nil {
log.Errorf("http url[%s] result[%s] error :%s", reqUrl, string(rspBody), err.Error())
result, err := q.GetResult(rspBody)
if err != nil {
return "", err
}
if cast.ToInt(result["errcode"]) != 0 {
log.Errorf("http url[%s] result[%s] error ", reqUrl, string(rspBody))
return "", errors.New(string(rspBody))
}
return cast.ToString(result["openid"]), nil
}
func (q *QyWeixin) GetUserInfo(userid string) (*UserInfo, error) {
if err := q.refreshToken(); err != nil {
return nil, err
}
reqUrl := fmt.Sprintf("%s?access_token=%s&userid=%s", urlGetUser, q.GetToken(), userid)
rspBody, err := butil.HttpGet(reqUrl, nil)
if err != nil {
log.Errorf("httpPost url[%s] error :%s", reqUrl, err.Error())
return nil, err
}
result, err := q.GetResult(rspBody)
if err != nil {
return nil, err
}
userInfo := new(UserInfo)
userInfo.UserId = userid
userInfo.RealName = cast.ToString(result["name"])
return userInfo, nil
}
func (q *QyWeixin) refreshToken() error {
if time.Now().Unix() <= q.tokenExpire-600 {
return nil
@ -74,15 +110,10 @@ func (q *QyWeixin) refreshToken() error {
log.Errorf("http url[%s] error :%s", reqUrl, err.Error())
return err
}
result := make(map[string]interface{})
if err := json.Unmarshal(rspBody, &result); err != nil {
log.Errorf("http url[%s] result[%s] error :%s", reqUrl, string(rspBody), err.Error())
result, err := q.GetResult(rspBody)
if err != nil {
return err
}
if cast.ToInt(result["errcode"]) != 0 {
log.Errorf("http url[%s] result[%s] error ", reqUrl, string(rspBody))
return errors.New(string(rspBody))
}
q.Token = cast.ToString(result["access_token"])
q.tokenExpire = time.Now().Unix() + cast.ToInt64(result["expires_in"])

View File

@ -0,0 +1,116 @@
package weixin
import (
butil "enterprise/base/util"
"fmt"
log "github.com/sirupsen/logrus"
"github.com/smbrave/goutil"
"github.com/spf13/cast"
"time"
)
var (
urlQyWeixinHrGetAllField = "https://qyapi.weixin.qq.com/cgi-bin/hr/get_fields"
urlQyWeixinHrGetStaffInfo = "https://qyapi.weixin.qq.com/cgi-bin/hr/get_staff_info"
)
type QyWeixinHR struct {
QyWeixin
}
type StaffInfo struct {
UserName string
RealName string
Phone string
Idno string
Salary float64
Stock float64
EntryDate string
BirthDate string
OfficialDate string
BankName string
BankCard string
}
func NewQyWeixinHR(corpId, secret, agent string) *QyWeixinHR {
return &QyWeixinHR{
QyWeixin: QyWeixin{
CorpId: corpId,
Secret: secret,
Agent: agent,
},
}
}
func (h *QyWeixinHR) GetStaffInfo(userId string) (*StaffInfo, error) {
reqUrl := fmt.Sprintf("%s?access_token=%s", urlQyWeixinHrGetStaffInfo, h.GetToken())
reqBody := make(map[string]interface{})
reqBody["userid"] = userId
reqBody["get_all"] = true
rspBody, err := butil.HttpPostJson(reqUrl, nil, []byte(goutil.EncodeJSON(reqBody)))
if err != nil {
return nil, err
}
staff := new(StaffInfo)
result, err := h.GetResult(rspBody)
if err != nil {
return nil, err
}
fieldMap := make(map[string]map[string]interface{})
for _, fieldInfo := range cast.ToSlice(result["field_info"]) {
fi := cast.ToStringMap(fieldInfo)
fieldMap[cast.ToString(fi["fieldid"])] = fi
}
userInfo, err := h.GetUserInfo(userId)
if err != nil {
log.Errorf("GetUserInfo error:%s", err.Error())
return nil, err
}
staff.UserName = userId
staff.RealName = userInfo.RealName
staff.Salary = cast.ToFloat64(h.getFieldValue(fieldMap["20001"]))
staff.Stock = cast.ToFloat64(h.getFieldValue(fieldMap["20002"]))
staff.Phone = cast.ToString(h.getFieldValue(fieldMap["17003"]))
staff.Idno = cast.ToString(h.getFieldValue(fieldMap["11015"]))
staff.BankName = cast.ToString(h.getFieldValue(fieldMap["13001"]))
staff.BankCard = cast.ToString(h.getFieldValue(fieldMap["13002"]))
staff.EntryDate = time.Unix(cast.ToInt64(h.getFieldValue(fieldMap["12018"])), 0).Format("2006-01-02")
staff.BirthDate = time.Unix(cast.ToInt64(h.getFieldValue(fieldMap["11005"])), 0).Format("2006-01-02")
staff.OfficialDate = time.Unix(cast.ToInt64(h.getFieldValue(fieldMap["12023"])), 0).Format("2006-01-02")
//fmt.Println(goutil.EncodeJSON(staff))
return staff, nil
}
func (h *QyWeixinHR) getFieldValue(fieldInfo map[string]interface{}) string {
valueType := cast.ToInt(fieldInfo["value_type"])
if valueType == 1 {
return cast.ToString(fieldInfo["value_string"])
} else if valueType == 2 {
return cast.ToString(fieldInfo["value_uint64"])
} else if valueType == 3 {
return cast.ToString(fieldInfo["value_uint32"])
} else if valueType == 4 {
return cast.ToString(fieldInfo["value_int64"])
} else if valueType == 5 {
moble := cast.ToStringMap(fieldInfo["value_mobile"])
return cast.ToString(moble["value_mobile"])
}
return ""
}
func (h *QyWeixinHR) GetAllField() ([]byte, error) {
reqUrl := fmt.Sprintf("%s?access_token=%s", urlQyWeixinHrGetAllField, h.GetToken())
rspBody, err := butil.HttpGet(reqUrl, nil)
if err != nil {
return nil, err
}
result, err := h.GetResult(rspBody)
if err != nil {
return nil, err
}
fmt.Println(goutil.EncodeJSONIndent(result))
return rspBody, err
}

439
conf/hr_assiant.json Normal file
View File

@ -0,0 +1,439 @@
{
"errcode": 0,
"errmsg": "ok",
"group_list": [{
"field_list": [{
"field_name": "出生日期",
"field_type": 3,
"fieldid": 11005,
"is_must": false
},
{
"field_name": "年龄",
"field_type": 1,
"fieldid": 11006,
"is_must": false
},
{
"field_name": "籍贯",
"field_type": 2,
"fieldid": 11007,
"is_must": false
},
{
"field_name": "民族",
"field_type": 2,
"fieldid": 11008,
"is_must": false
},
{
"field_name": "婚姻状况",
"field_type": 2,
"fieldid": 11009,
"is_must": false
},
{
"field_name": "政治面貌",
"field_type": 2,
"fieldid": 11010,
"is_must": false
},
{
"field_name": "首次参加工作日期",
"field_type": 3,
"fieldid": 11011,
"is_must": false
},
{
"field_name": "社会工龄",
"field_type": 1,
"fieldid": 11012,
"is_must": false
},
{
"field_name": "工龄区间",
"field_type": 2,
"fieldid": 11013,
"is_must": false
},
{
"field_name": "身份证号码",
"field_type": 1,
"fieldid": 11015,
"is_must": false
},
{
"field_name": "户口类型",
"field_type": 2,
"fieldid": 11017,
"is_must": false
},
{
"field_name": "现居住地址",
"field_type": 1,
"fieldid": 11020,
"is_must": false
},
{
"field_name": "社保账号",
"field_type": 1,
"fieldid": 11021,
"is_must": false
},
{
"field_name": "公积金账号",
"field_type": 1,
"fieldid": 11022,
"is_must": false
}
],
"group_id": 1001,
"group_name": "个人信息"
},
{
"field_list": [{
"field_name": "工号",
"field_type": 1,
"fieldid": 12024,
"is_must": false
},
{
"field_name": "员工类型",
"field_type": 2,
"fieldid": 12003,
"is_must": false
},
{
"field_name": "员工状态",
"field_type": 2,
"fieldid": 12004,
"is_must": false
},
{
"field_name": "入职日期",
"field_type": 3,
"fieldid": 12018,
"is_must": false
},
{
"field_name": "试用期",
"field_type": 2,
"fieldid": 12021,
"is_must": false
},
{
"field_name": "转正日期",
"field_type": 3,
"fieldid": 12023,
"is_must": false
},
{
"field_name": "职位",
"field_type": 2,
"fieldid": 12010,
"is_must": false
},
{
"field_name": "职级",
"field_type": 2,
"fieldid": 12011,
"is_must": false
},
{
"field_name": "办公地点",
"field_type": 2,
"fieldid": 12014,
"is_must": false
},
{
"field_name": "座位号",
"field_type": 1,
"fieldid": 12015,
"is_must": false
},
{
"field_name": "招聘类型",
"field_type": 1,
"fieldid": 12016,
"is_must": false
},
{
"field_name": "司龄",
"field_type": 1,
"fieldid": 12019,
"is_must": false
},
{
"field_name": "司龄区间",
"field_type": 2,
"fieldid": 12020,
"is_must": false
}
],
"group_id": 1002,
"group_name": "在职信息"
},
{
"field_list": [{
"field_name": "开户行",
"field_type": 1,
"fieldid": 13001,
"is_must": false
},
{
"field_name": "银行卡号",
"field_type": 1,
"fieldid": 13002,
"is_must": false
}
],
"group_id": 1003,
"group_name": "银行卡信息"
},
{
"field_list": [{
"field_name": "学历",
"field_type": 2,
"fieldid": 14001,
"is_must": true
},
{
"field_name": "毕业院校",
"field_type": 1,
"fieldid": 14002,
"is_must": true
},
{
"field_name": "入学时间",
"field_type": 3,
"fieldid": 14003,
"is_must": true
},
{
"field_name": "毕业时间",
"field_type": 3,
"fieldid": 14004,
"is_must": false
},
{
"field_name": "专业",
"field_type": 1,
"fieldid": 14005,
"is_must": false
},
{
"field_name": "学位",
"field_type": 2,
"fieldid": 14006,
"is_must": false
}
],
"group_id": 1004,
"group_name": "教育经历"
},
{
"field_list": [{
"field_name": "前公司",
"field_type": 1,
"fieldid": 15001,
"is_must": true
},
{
"field_name": "前公司部门",
"field_type": 1,
"fieldid": 15002,
"is_must": false
},
{
"field_name": "前公司职位",
"field_type": 1,
"fieldid": 15003,
"is_must": false
},
{
"field_name": "开始日期",
"field_type": 3,
"fieldid": 15004,
"is_must": true
},
{
"field_name": "结束日期",
"field_type": 3,
"fieldid": 15005,
"is_must": false
},
{
"field_name": "工作描述",
"field_type": 1,
"fieldid": 15006,
"is_must": false
}
],
"group_id": 1005,
"group_name": "工作经历"
},
{
"field_list": [{
"field_name": "紧急联系人姓名",
"field_type": 1,
"fieldid": 17001,
"is_must": true
},
{
"field_name": "紧急联系人关系",
"field_type": 2,
"fieldid": 17002,
"is_must": false
},
{
"field_name": "紧急联系人手机",
"field_type": 1,
"fieldid": 17003,
"is_must": true
},
{
"field_name": "紧急联系人住址",
"field_type": 1,
"fieldid": 17004,
"is_must": false
}
],
"group_id": 1006,
"group_name": "紧急联系人"
},
{
"field_list": [{
"field_name": "家人姓名",
"field_type": 1,
"fieldid": 16001,
"is_must": true
},
{
"field_name": "家人关系",
"field_type": 2,
"fieldid": 16002,
"is_must": true
},
{
"field_name": "家人手机",
"field_type": 1,
"fieldid": 16003,
"is_must": false
},
{
"field_name": "家人住址",
"field_type": 1,
"fieldid": 16004,
"is_must": false
}
],
"group_id": 1007,
"group_name": "家庭成员"
},
{
"field_list": [{
"field_name": "合同公司",
"field_type": 1,
"fieldid": 18001,
"is_must": false
},
{
"field_name": "合同类型",
"field_type": 2,
"fieldid": 18002,
"is_must": false
},
{
"field_name": "合同起始日",
"field_type": 3,
"fieldid": 18003,
"is_must": true
},
{
"field_name": "合同到期日",
"field_type": 3,
"fieldid": 18004,
"is_must": true
},
{
"field_name": "续签次数",
"field_type": 1,
"fieldid": 18007,
"is_must": false
},
{
"field_name": "合同附件",
"field_type": 6,
"fieldid": 18008,
"is_must": false
}
],
"group_id": 1008,
"group_name": "合同记录"
},
{
"field_list": [{
"field_name": "员工照片",
"field_type": 4,
"fieldid": 19001,
"is_must": false
},
{
"field_name": "身份证人像面",
"field_type": 4,
"fieldid": 19002,
"is_must": false
},
{
"field_name": "身份证国徽面",
"field_type": 4,
"fieldid": 19003,
"is_must": false
},
{
"field_name": "学位证书",
"field_type": 4,
"fieldid": 19004,
"is_must": false
},
{
"field_name": "毕业证书",
"field_type": 4,
"fieldid": 19005,
"is_must": false
},
{
"field_name": "前公司离职证明",
"field_type": 4,
"fieldid": 19006,
"is_must": false
},
{
"field_name": "奖励证明",
"field_type": 4,
"fieldid": 19007,
"is_must": false
}
],
"group_id": 1009,
"group_name": "材料附件"
},
{
"field_list": [{
"field_name": "基本工资",
"field_type": 1,
"fieldid": 20001,
"is_must": false
},
{
"field_name": "奋斗股",
"field_type": 1,
"fieldid": 20002,
"is_must": false
}
],
"group_id": 10001,
"group_name": "薪酬福利"
}
]
}

View File

@ -27,7 +27,6 @@ approve_agent = "3010040"
checkin_agent = "3010011"
checkin_secret = "6ljYNGt4DonZLmr9SCtgkTlOvtqmsOchBrTWwGl_GpU"
checkin_group = "1,2"
checkin_pay_title = "工作餐补贴"
checkin_pay_thresold = 11
pay_secret = "JCGsxntR4E7wrEEQvWGr8_wdKtRlw48n-W6zd8lbwc4"
pay_agent = "3010046"

View File

@ -26,7 +26,6 @@ approve_secret = "xJOClC5V2pPon1azgrAzf5kq1TB72xZ3ScR7O5G3lQo"
checkin_agent = "3010011"
checkin_secret = "6ljYNGt4DonZLmr9SCtgkTlOvtqmsOchBrTWwGl_GpU"
checkin_group = "1,2"
checkin_pay_title = "工作餐补贴"
checkin_pay_thresold = 11
pay_secret = "JCGsxntR4E7wrEEQvWGr8_wdKtRlw48n-W6zd8lbwc4"
pay_agent = "3010046"

View File

@ -0,0 +1,3 @@
package service
type HrAssiant struct{}

56
worker/staff.go Normal file
View File

@ -0,0 +1,56 @@
package worker
import (
"enterprise/common/config"
"enterprise/common/dao"
"enterprise/common/model"
"enterprise/common/weixin"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
)
func SyncStaffInfo() {
cfg := config.GetConfig()
hrAssiant := weixin.NewQyWeixinHR(cfg.QyWeixin.Corpid, cfg.QyWeixin.HrSecret, cfg.QyWeixin.HrSecret)
userConfigs, err := dao.NewUserConfigDao().Query(model.UserConfigStatusNormal)
if err != nil {
log.Errorf("query staff db error :%s", err.Error())
return
}
for _, user := range userConfigs {
staffInfo, err := hrAssiant.GetStaffInfo(user.Username)
if err != nil {
log.Errorf("getstaff info username[%s] error :%s", user.Username, err.Error())
continue
}
staff, err := dao.NewStaffInfoDao().GetByUsername(user.Username)
if err != nil {
log.Errorf("db error :%s", err.Error())
continue
}
if staff == nil {
staff = new(model.StaffInfo)
}
staff.Username = staffInfo.UserName
staff.Realname = staffInfo.RealName
staff.Phone = staffInfo.Phone
staff.Idno = staffInfo.Idno
staff.Salary = cast.ToString(staffInfo.Salary)
staff.EntryDate = staffInfo.EntryDate
staff.OfficialDate = staffInfo.OfficialDate
staff.BirthDate = staffInfo.BirthDate
staff.BankName = staffInfo.BankName
staff.BankCard = staffInfo.BankCard
if staff.Id == 0 {
_, err = dao.NewStaffInfoDao().Create(staff)
} else {
err = dao.NewStaffInfoDao().Update(staff)
}
if err != nil {
log.Errorf("db error :%s", err.Error())
}
}
}

View File

@ -20,6 +20,10 @@ func Init() error {
go SyncCheckin(time.Now().Format("2006-01-02"))
})
cron.Every(1).Day().At("03:00").Do(func() {
go SyncStaffInfo()
})
cron.StartAsync()
return nil
}