From 6f409296d500d501dbec3c5437b62c32d3466fa4 Mon Sep 17 00:00:00 2001 From: jiangyong27 Date: Wed, 9 Aug 2023 22:00:55 +0800 Subject: [PATCH] auto pay --- cmd/enterprise.go | 12 +++-- common/config/config.go | 18 ++++--- common/dao/checkin_money.go | 68 +++++++++++++++++++++++++ common/model/checkin_money.go | 12 +++++ common/{qyweixin => weixin}/checkin.go | 2 +- common/{qyweixin => weixin}/params.go | 2 +- common/{qyweixin => weixin}/qypay.go | 46 ++++++++++++----- common/{qyweixin => weixin}/qyweixin.go | 25 ++++++++- conf/server.conf.prod | 2 + worker/autopay.go | 60 +++++++++++++++++++++- worker/checkin.go | 9 ++-- worker/worker.go | 2 +- 12 files changed, 226 insertions(+), 32 deletions(-) create mode 100644 common/dao/checkin_money.go create mode 100644 common/model/checkin_money.go rename common/{qyweixin => weixin}/checkin.go (87%) rename common/{qyweixin => weixin}/params.go (99%) rename common/{qyweixin => weixin}/qypay.go (75%) rename common/{qyweixin => weixin}/qyweixin.go (83%) diff --git a/cmd/enterprise.go b/cmd/enterprise.go index 287aff9..1e6cc72 100644 --- a/cmd/enterprise.go +++ b/cmd/enterprise.go @@ -3,7 +3,7 @@ package main import ( "enterprise/common/config" "enterprise/common/global" - "enterprise/common/qyweixin" + "enterprise/common/weixin" "enterprise/server" "enterprise/worker" ) @@ -22,10 +22,14 @@ func main() { func main2() { config.LoadServerConfig() - global.InitGlobal() + //global.InitGlobal() - pay := qyweixin.NewQyPay() - if err := pay.PayRedMoney(); err != nil { + pay := weixin.NewQyPay() + if err := pay.PayRedMoney(&weixin.RedMoneyReq{ + TotalAmount: 200, + Title: "加班补贴", + Userid: "jiangyong", + }); err != nil { panic(err) } } diff --git a/common/config/config.go b/common/config/config.go index c712e5a..8787078 100644 --- a/common/config/config.go +++ b/common/config/config.go @@ -36,17 +36,21 @@ type Redis struct { } type QyWeixin struct { - Corpid string `toml:"corpid"` + Corpid string `toml:"corpid"` + CheckinAgent string `toml:"checkin_agent"` CheckinSecret string `toml:"checkin_secret"` CheckinGroup string `toml:"checkin_group"` + CheckinPayMoney string `toml:"checkin_pay_money"` + CheckinPayTitle string `toml:"checkin_pay_title"` CheckinPayThresold float64 `toml:"checkin_pay_thresold"` - EnterpriseAgent string `toml:"enterprise_agent"` - EnterpriseSecret string `toml:"enterprise_secret"` - HrAgent string `toml:"hr_agent"` - HrSecret string `toml:"hr_secret"` - PaySecret string `toml:"pay_secret"` - PayAgent string `toml:"pay_agent"` + + EnterpriseAgent string `toml:"enterprise_agent"` + EnterpriseSecret string `toml:"enterprise_secret"` + HrAgent string `toml:"hr_agent"` + HrSecret string `toml:"hr_secret"` + PaySecret string `toml:"pay_secret"` + PayAgent string `toml:"pay_agent"` } type WxPay struct { diff --git a/common/dao/checkin_money.go b/common/dao/checkin_money.go new file mode 100644 index 0000000..2e31af8 --- /dev/null +++ b/common/dao/checkin_money.go @@ -0,0 +1,68 @@ +package dao + +import ( + "enterprise/common/model" + "gorm.io/gorm" + "time" +) + +type CheckinMoneyDao struct { +} + +func NewCheckinMoneyDao() *CheckinMoneyDao { + return &CheckinMoneyDao{} +} + +func (d *CheckinMoneyDao) TableName() string { + return "checkin_money" +} + +func (d *CheckinMoneyDao) Create(o *model.CheckinMoney) (int64, error) { + o.CreateTime = time.Now().Unix() + res := GetDB().Table(d.TableName()).Create(o) + return o.Id, res.Error +} + +func (d *CheckinMoneyDao) Update(o *model.CheckinMoney) error { + o.UpdateTime = time.Now().Unix() + tx := GetDB().Table(d.TableName()) + res := tx.Save(o) + return res.Error +} + +func (d *CheckinMoneyDao) Delete(id int64) error { + res := GetDB().Table(d.TableName()).Delete(&model.CheckinMoney{}, id) + return res.Error +} + +func (d *CheckinMoneyDao) Get(id int64) (*model.CheckinMoney, error) { + var u model.CheckinMoney + 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 *CheckinMoneyDao) GetByDay(userId, day, checkinType string) (*model.CheckinMoney, error) { + var u model.CheckinMoney + tx := GetDB().Table(d.TableName()) + tx = tx.Where("user_id = ?", userId) + tx = tx.Where("checkin_type = ?", checkinType) + tx = tx.Where("day = ?", day) + res := tx.First(&u) + if res.Error == gorm.ErrRecordNotFound { + return nil, nil + } + + if res.Error != nil { + return nil, res.Error + } + return &u, nil +} diff --git a/common/model/checkin_money.go b/common/model/checkin_money.go new file mode 100644 index 0000000..80e8458 --- /dev/null +++ b/common/model/checkin_money.go @@ -0,0 +1,12 @@ +package model + +type CheckinMoney struct { + Id int64 + Day string + Userid string + CheckinId int64 + CheckinType string + BillNo string + CreateTime int64 + UpdateTime int64 +} diff --git a/common/qyweixin/checkin.go b/common/weixin/checkin.go similarity index 87% rename from common/qyweixin/checkin.go rename to common/weixin/checkin.go index cb13ae8..d5fd5d2 100644 --- a/common/qyweixin/checkin.go +++ b/common/weixin/checkin.go @@ -1,4 +1,4 @@ -package qyweixin +package weixin type UserCheckIn struct { UserId string diff --git a/common/qyweixin/params.go b/common/weixin/params.go similarity index 99% rename from common/qyweixin/params.go rename to common/weixin/params.go index 13b31c9..5210e27 100644 --- a/common/qyweixin/params.go +++ b/common/weixin/params.go @@ -1,4 +1,4 @@ -package qyweixin +package weixin import ( "bytes" diff --git a/common/qyweixin/qypay.go b/common/weixin/qypay.go similarity index 75% rename from common/qyweixin/qypay.go rename to common/weixin/qypay.go index 61d6c85..c23394f 100644 --- a/common/qyweixin/qypay.go +++ b/common/weixin/qypay.go @@ -1,4 +1,4 @@ -package qyweixin +package weixin import ( "bytes" @@ -10,6 +10,7 @@ import ( "fmt" log "github.com/sirupsen/logrus" "github.com/smbrave/goutil" + "github.com/spf13/cast" "github.com/wechatpay-apiv3/wechatpay-go/core" "github.com/wechatpay-apiv3/wechatpay-go/core/option" "github.com/wechatpay-apiv3/wechatpay-go/utils" @@ -18,10 +19,18 @@ import ( "time" ) +type RedMoneyReq struct { + TotalAmount int64 + Title string + Userid string + BillNo string +} + type QyPay struct { cli *core.Client tlsClient *http.Client stdClient *http.Client + qyClient *QyWeixin } func NewQyPay() *QyPay { @@ -38,6 +47,7 @@ func NewQyPay() *QyPay { } pay.tlsClient = client + pay.qyClient = NewQyWeixin(cfg.QyWeixin.Corpid, cfg.QyWeixin.HrSecret) return pay } @@ -109,7 +119,7 @@ func (w *QyPay) initPay() error { return nil } -func (p *QyPay) PayRedMoney() error { +func (p *QyPay) PayRedMoney(req *RedMoneyReq) error { if p.cli == nil { if err := p.initPay(); err != nil { return err @@ -117,16 +127,24 @@ func (p *QyPay) PayRedMoney() error { } cfg := config.GetConfig() param := newParams() + userOpenid, err := p.qyClient.GetOpenid(req.Userid) + if err != nil { + log.Errorf("get openid error :%s", err.Error()) + return err + } + if req.BillNo == "" { + req.BillNo = fmt.Sprintf("QY%s%s", time.Now().Format("20060102150405"), butil.RandomStr(6)) + } param.Set("nonce_str", butil.RandomStr(32)) - param.Set("mch_billno", fmt.Sprintf("QY%s%s", time.Now().Format("20060102150405"), butil.RandomStr(6))) + param.Set("mch_billno", req.BillNo) param.Set("mch_id", cfg.WxPay.PayMchId) param.Set("wxappid", cfg.QyWeixin.Corpid) - param.Set("agentid", "1") - param.Set("re_openid", "oZZmL6Lx7Rj3vbNRXgA3ZpwU_tzM") - param.Set("total_amount", "100") - param.Set("wishing", "感谢您参加猜灯谜活动,祝您元宵节快乐!") - param.Set("act_name", "猜灯谜抢红包活动") - param.Set("remark", "猜越多得越多,快来抢!") + param.Set("agentid", cfg.QyWeixin.PayAgent) + param.Set("re_openid", userOpenid) + param.Set("total_amount", cast.ToString(req.TotalAmount)) + param.Set("wishing", req.Title) + param.Set("act_name", "企业红包") + param.Set("remark", "企业红包") param.Set("workwx_sign", param.QySignMd5(cfg.QyWeixin.PaySecret)) param.Set("sign", param.SignMd5(cfg.WxPay.PayApiKeyV2)) @@ -139,7 +157,11 @@ func (p *QyPay) PayRedMoney() error { respParam := newParams() respParam.Decode(rspBody) - fmt.Println("req:", string(param.Encode())) - fmt.Println("resp: ", string(respParam.Encode())) - return nil + + returnCode := respParam.GetString("return_code") + resultCoce := respParam.GetString("result_code") + if resultCoce == "SUCCESS" && returnCode == "SUCCESS" { + return nil + } + return errors.New(string(respParam.Encode())) } diff --git a/common/qyweixin/qyweixin.go b/common/weixin/qyweixin.go similarity index 83% rename from common/qyweixin/qyweixin.go rename to common/weixin/qyweixin.go index fe4b25f..d33f17c 100644 --- a/common/qyweixin/qyweixin.go +++ b/common/weixin/qyweixin.go @@ -1,4 +1,4 @@ -package qyweixin +package weixin import ( "encoding/json" @@ -18,6 +18,7 @@ var ( urlGetToken = "https://qyapi.weixin.qq.com/cgi-bin/gettoken" 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" ) type QyWeixin struct { @@ -161,3 +162,25 @@ func (q *QyWeixin) GetCheckinData(day, userId string) (*UserCheckIn, error) { } return userData, nil } + +func (q *QyWeixin) GetOpenid(userid string) (string, error) { + if err := q.refreshToken(); err != nil { + return "", err + } + reqUrl := fmt.Sprintf("%s?access_token=%s", urlConvertOpenid, q.token) + rspBody, err := butil.HttpPostJson(reqUrl, nil, []byte(fmt.Sprintf(`{"userid" : "%s"}`, userid))) + if err != nil { + 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()) + 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 +} diff --git a/conf/server.conf.prod b/conf/server.conf.prod index b90c27b..33d6aa3 100644 --- a/conf/server.conf.prod +++ b/conf/server.conf.prod @@ -24,6 +24,8 @@ enterprise_secret = "oMB24UhKe50-XPTg7vhnwoTuhEXaq5XeiHPAUtF4hOs" checkin_agent = "3010011" checkin_secret = "6ljYNGt4DonZLmr9SCtgkTlOvtqmsOchBrTWwGl_GpU" checkin_group = "1,2" +checkin_pay_money = 20 +checkin_pay_title = "工作餐补贴" checkin_pay_thresold = 11 pay_secret = "JCGsxntR4E7wrEEQvWGr8_wdKtRlw48n-W6zd8lbwc4" pay_agent = "3010046" diff --git a/worker/autopay.go b/worker/autopay.go index 0ce94f9..992777a 100644 --- a/worker/autopay.go +++ b/worker/autopay.go @@ -1,19 +1,23 @@ package worker import ( + butil "enterprise/base/util" "enterprise/common/config" + "enterprise/common/dao" "enterprise/common/global" "enterprise/common/model" + "enterprise/common/weixin" "fmt" log "github.com/sirupsen/logrus" "github.com/smbrave/goutil" + "github.com/spf13/cast" "strings" "time" ) -func ViewCheckin(checkin *model.Checkin) { +func NotifyCheckinOffDuty(checkin *model.Checkin) { if checkin.Exception != "" { - log.Errorf("execption[%s] %s", checkin.Exception, goutil.EncodeJSON(checkin)) + log.Infof("execption[%s] %s", checkin.Exception, goutil.EncodeJSON(checkin)) return } thresold := config.GetConfig().QyWeixin.CheckinPayThresold @@ -21,7 +25,47 @@ func ViewCheckin(checkin *model.Checkin) { if duration < int64(3600*thresold) { return } + autoPayMoney(checkin, "下班打卡") +} + +func NotifyCheckinOnDuty(checkin *model.Checkin) { message := make([]string, 0) + message = append(message, "【上班提醒】") + message = append(message, fmt.Sprintf("员工名称:%s", checkin.UserId)) + message = append(message, fmt.Sprintf("考勤日期:%s", checkin.Day)) + message = append(message, fmt.Sprintf("开始时间:%s", goutil.TimeToDateTime(checkin.StartTime))) + + if err := global.SendMessage([]string{"jiangyong"}, strings.Join(message, "\n")); err != nil { + log.Errorf("send message error :%s", err.Error()) + } +} + +func autoPayMoney(checkin *model.Checkin, checkinType string) error { + cfg := config.GetConfig() + + checkinMoneyDao := dao.NewCheckinMoneyDao() + checkinMoney, err := checkinMoneyDao.GetByDay(checkin.UserId, checkin.Day, checkinType) + if err != nil { + log.Errorf("db error :%s", err.Error()) + return err + } + if checkinMoney != nil { + return nil + } + + var req weixin.RedMoneyReq + req.TotalAmount = cast.ToInt64(cfg.QyWeixin.CheckinPayMoney) * 100 + req.Title = cfg.QyWeixin.CheckinPayTitle + req.BillNo = fmt.Sprintf("QY%s%s", time.Now().Format("20060102150405"), butil.RandomStr(6)) + req.Userid = "jiangyong" + if err := weixin.NewQyPay().PayRedMoney(&req); err != nil { + log.Errorf("pay red money error :%s", err.Error()) + return err + } + + message := make([]string, 0) + duration := checkin.EndTime - checkin.StartTime + message = append(message, "【下班提醒】") message = append(message, fmt.Sprintf("员工名称:%s", checkin.UserId)) message = append(message, fmt.Sprintf("考勤日期:%s", checkin.Day)) message = append(message, fmt.Sprintf("开始时间:%s", goutil.TimeToDateTime(checkin.StartTime))) @@ -31,4 +75,16 @@ func ViewCheckin(checkin *model.Checkin) { if err := global.SendMessage([]string{"jiangyong"}, strings.Join(message, "\n")); err != nil { log.Errorf("send message error :%s", err.Error()) } + + checkinMoney = new(model.CheckinMoney) + checkinMoney.CheckinId = checkin.Id + checkinMoney.BillNo = req.BillNo + checkinMoney.CheckinType = checkinType + checkinMoney.Day = checkin.Day + if _, err := checkinMoneyDao.Create(checkinMoney); err != nil { + log.Errorf("create checkinMoney model error :%s", err.Error()) + return err + } + + return nil } diff --git a/worker/checkin.go b/worker/checkin.go index b46b87c..b7408f9 100644 --- a/worker/checkin.go +++ b/worker/checkin.go @@ -4,14 +4,14 @@ import ( "enterprise/common/config" "enterprise/common/dao" "enterprise/common/model" - "enterprise/common/qyweixin" + "enterprise/common/weixin" log "github.com/sirupsen/logrus" "strings" ) func SyncCheckin(day string) error { cfg := config.GetConfig() - qyw := qyweixin.NewQyWeixin(cfg.QyWeixin.Corpid, cfg.QyWeixin.CheckinSecret) + qyw := weixin.NewQyWeixin(cfg.QyWeixin.Corpid, cfg.QyWeixin.CheckinSecret) users, err := qyw.GetCheckinEmployee(strings.Split(cfg.QyWeixin.CheckinGroup, ",")) if err != nil { return err @@ -62,8 +62,11 @@ func SyncCheckin(day string) error { if err != nil { log.Errorf("db error :%s", err.Error()) } + if isNew { + go NotifyCheckinOnDuty(checkin) + } if isUpdate { - go ViewCheckin(checkin) + go NotifyCheckinOffDuty(checkin) } } diff --git a/worker/worker.go b/worker/worker.go index 055fc9e..0c66c30 100644 --- a/worker/worker.go +++ b/worker/worker.go @@ -16,7 +16,7 @@ func Init1() error { func Init() error { timezone, _ := time.LoadLocation("Asia/Shanghai") cron := gocron.NewScheduler(timezone) - cron.Every(5).Minute().Do(func() { + cron.Every(1).Minute().Do(func() { go SyncCheckin(time.Now().Format("2006-01-02")) })