From 0a87aec351da3575bb57807028949c9ef0040785 Mon Sep 17 00:00:00 2001
From: jiangyong27 <yong27@163.com>
Date: Thu, 3 Apr 2025 12:54:19 +0800
Subject: [PATCH] autopay

---
 common/global/message.go           | 62 +++++++++++++++++++++++++++++-
 common/model/staff_salary.go       |  7 ++++
 server/controller/payment.go       |  7 +++-
 server/service/payment.go          | 40 +++++++++++++++++++
 server/service/staff_salary.go     |  4 +-
 server/service/staff_user.go       |  5 ++-
 {server/service => service}/pay.go | 39 ++-----------------
 worker/staff.go                    | 52 +++++++++++++++++++++++--
 worker/worker.go                   |  3 +-
 9 files changed, 173 insertions(+), 46 deletions(-)
 rename {server/service => service}/pay.go (75%)

diff --git a/common/global/message.go b/common/global/message.go
index a7762e6..1bcb3ce 100644
--- a/common/global/message.go
+++ b/common/global/message.go
@@ -3,16 +3,21 @@ package global
 import (
 	"context"
 	"enterprise/common/config"
+	"enterprise/common/dao"
 	"github.com/ArtisanCloud/PowerWeChat/v3/src/work"
 	"github.com/ArtisanCloud/PowerWeChat/v3/src/work/message/request"
+	"github.com/gogap/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/smbrave/goutil"
 	"github.com/spf13/cast"
 	"strings"
+	"sync"
 )
 
 var (
-	wxEnterprise *work.Work
+	wxEnterprise        *work.Work
+	corpEnterprise      map[int64]*work.Work
+	corpEnterpriseMutex sync.Mutex
 )
 
 func initWxWork() (*work.Work, error) {
@@ -34,6 +39,40 @@ func initWxWork() (*work.Work, error) {
 	return client, nil
 }
 
+func getWxWork(corpId int64) (*work.Work, error) {
+	if c, ok := corpEnterprise[corpId]; ok {
+		return c, nil
+	}
+
+	corp, err := dao.NewCorpDao().Get(corpId)
+	if err != nil {
+		return nil, err
+	}
+	if corp == nil {
+		return nil, errors.New("corp not exist")
+	}
+
+	cfg := corp.GetConfig()
+	client, err := work.NewWork(&work.UserConfig{
+		CorpID:  cfg.CorpId,
+		AgentID: cast.ToInt(cfg.PayAgent),
+		Secret:  cfg.PaySecret,
+		OAuth: work.OAuth{
+			Callback: "https://wecom.artisan-cloud.com/callback",
+			Scopes:   nil,
+		},
+	})
+	if err != nil {
+		log.Errorf("config[%s] init error : %s", goutil.EncodeJSON(cfg), err.Error())
+		return nil, err
+	}
+	corpEnterpriseMutex.Lock()
+	corpEnterprise[corpId] = client
+	corpEnterpriseMutex.Unlock()
+
+	return client, nil
+}
+
 func SendMessage(user []string, content string) error {
 	if wxEnterprise == nil {
 		wxM, err := initWxWork()
@@ -56,3 +95,24 @@ func SendMessage(user []string, content string) error {
 	}
 	return nil
 }
+
+func SendCorpMessage(corpId int64, user []string, content string) error {
+	client, _ := getWxWork(corpId)
+	if client == nil {
+		return errors.New("client error ")
+	}
+
+	corp, _ := dao.NewCorpDao().Get(corpId)
+	receivers := user
+	message := &request.RequestMessageSendText{}
+	message.ToUser = strings.Join(receivers, "|")
+	message.MsgType = "text"
+	message.AgentID = cast.ToInt(corp.GetConfig().PayAgent)
+	message.Text = &request.RequestText{Content: content}
+
+	if _, err := client.Message.SendText(context.Background(), message); err != nil {
+		log.Errorf("send message [%s] error : %s", goutil.EncodeJSON(message), err)
+		return err
+	}
+	return nil
+}
diff --git a/common/model/staff_salary.go b/common/model/staff_salary.go
index d02fc86..4d5ef8e 100644
--- a/common/model/staff_salary.go
+++ b/common/model/staff_salary.go
@@ -3,6 +3,7 @@ package model
 import (
 	"encoding/json"
 	butil "enterprise/base/util"
+	"fmt"
 	"github.com/smbrave/goutil"
 	"github.com/spf13/cast"
 	"strings"
@@ -66,6 +67,12 @@ func (s *StaffSalary) SetExtra(key string, value interface{}) {
 	s.Extra = goutil.EncodeJSON(extra)
 }
 
+func (s *StaffSalary) GetBillUrl() string {
+	encId := goutil.EncryptID(s.Id, "@@salary@@")
+	billUrl := fmt.Sprintf("https://e.yubanqy.com/api/staff/salary/bill?id=%s", encId)
+	return billUrl
+}
+
 type StaffSalarySort []*StaffSalary
 
 func (s StaffSalarySort) Len() int {
diff --git a/server/controller/payment.go b/server/controller/payment.go
index 8c528dc..3ce484d 100644
--- a/server/controller/payment.go
+++ b/server/controller/payment.go
@@ -6,6 +6,7 @@ import (
 	"enterprise/server/api"
 	"enterprise/server/service"
 	"enterprise/server/session"
+	CommonService "enterprise/service"
 	"fmt"
 	"github.com/gin-gonic/gin"
 	"github.com/smbrave/goutil"
@@ -24,7 +25,7 @@ func (q *Payment) AlipayAuth(ctx *gin.Context) {
 	authCode := ctx.Query("auth_code")
 	state := ctx.Query("state")
 
-	userid, staffUser := service.NewPay().AlipayAuth(sess, authCode, state)
+	userid, staffUser := service.NewPayment().AlipayAuth(sess, authCode, state)
 	username := goutil.If(staffUser.Realname != "", staffUser.Realname, staffUser.Username)
 	ctx.HTML(http.StatusOK, "alipay.html", gin.H{
 		"title":   "绑定成功",
@@ -50,7 +51,9 @@ func (q *Payment) Pay(ctx *gin.Context) {
 	session.CheckDBError(err)
 	session.CheckNilError(user, fmt.Sprintf("用户[%s]不存在", req.Username))
 
-	service.NewPay().Pay(corp, user, req.Title, req.PayType, req.Amount)
+	if err = CommonService.NewPay().Pay(corp, user, req.Title, req.PayType, req.Amount); err != nil {
+		panic(config.ErrInternal.New().Append(err))
+	}
 	ctx.JSON(http.StatusOK, session.NewRspOk())
 }
 
diff --git a/server/service/payment.go b/server/service/payment.go
index 9842ca0..76af36e 100644
--- a/server/service/payment.go
+++ b/server/service/payment.go
@@ -1,9 +1,16 @@
 package service
 
 import (
+	"context"
+	"enterprise/common/config"
 	"enterprise/common/dao"
+	"enterprise/common/model"
 	"enterprise/server/api"
 	"enterprise/server/session"
+	log "github.com/sirupsen/logrus"
+	"github.com/smartwalle/alipay/v3"
+	"github.com/smbrave/goutil"
+	"github.com/spf13/cast"
 	"time"
 )
 
@@ -40,3 +47,36 @@ func (p *Payment) Suggest(sess *session.AdminSession, field string) interface{}
 	}
 	return counts
 }
+
+func (p *Payment) AlipayAuth(sess *session.AdminSession, authCode, state string) (string, *model.StaffUser) {
+
+	corp, err := dao.NewCorpDao().GetByHost(sess.GetHeader().Host)
+	session.CheckDBError(err)
+	session.CheckNilError(corp)
+	cli := config.GetAliPayClient("batiao")
+
+	var req alipay.SystemOauthToken
+	req.Code = authCode
+	req.GrantType = "authorization_code"
+	res, err := cli.SystemOauthToken(context.Background(), req)
+	if err != nil {
+		log.Errorf("error :%s", err.Error())
+		panic(config.ErrInternal.New().Append(err))
+	}
+	if !res.IsSuccess() {
+		log.Errorf(goutil.EncodeJSON(res))
+		panic(config.ErrInternal.New().Append(goutil.EncodeJSON(res)))
+	}
+
+	staffUser, err := dao.NewStaffUserDao().Get(cast.ToInt64(state))
+	session.CheckDBError(err)
+	session.CheckNilError(staffUser)
+	payee := staffUser.GetPayee()
+	oldUid := payee.AlipayUid
+	payee.AlipayUid = res.UserId
+	staffUser.Payee = goutil.EncodeJSON(payee)
+	err = dao.NewStaffUserDao().Update(staffUser)
+	session.CheckDBError(err)
+	log.Errorf("staffuser[%d] alipayUid[%s]->alipayUid[%s]", staffUser.Id, oldUid, res.UserId)
+	return res.UserId, staffUser
+}
diff --git a/server/service/staff_salary.go b/server/service/staff_salary.go
index eac4f4a..dd344d4 100644
--- a/server/service/staff_salary.go
+++ b/server/service/staff_salary.go
@@ -161,7 +161,9 @@ func (s *StaffSalary) Pay(sess *session.AdminSession, req *api.PaySalaryReq) {
 	salary.Status = model.StaffSalaryStatusPayed
 	dao.NewStaffSalaryDao().Update(salary)
 
-	NewPay().Pay(corp, user, title, req.PayType, int64(salary.GetRealSalary()*100))
+	if err = CommonService.NewPay().Pay(corp, user, title, req.PayType, int64(salary.GetRealSalary()*100)); err != nil {
+		panic(config.ErrInternal.New().Append(err))
+	}
 }
 
 func (s *StaffSalary) Agent(cid int64, month string, ctx *gin.Context) {
diff --git a/server/service/staff_user.go b/server/service/staff_user.go
index 92488cd..6f26017 100644
--- a/server/service/staff_user.go
+++ b/server/service/staff_user.go
@@ -7,6 +7,7 @@ import (
 	"enterprise/common/model"
 	"enterprise/server/api"
 	"enterprise/server/session"
+	CommonService "enterprise/service"
 	"git.u8t.cn/open/gosdk/qyweixin"
 	"github.com/google/uuid"
 	log "github.com/sirupsen/logrus"
@@ -209,7 +210,9 @@ func (s *StaffUser) Pay(sess *session.AdminSession, req *api.StaffPayReq) {
 	if req.Title == "" {
 		req.Title = "测试"
 	}
-	NewPay().Pay(corp, user, req.Title, req.PayType, cast.ToInt64(req.Amount))
+	if err = CommonService.NewPay().Pay(corp, user, req.Title, req.PayType, cast.ToInt64(req.Amount)); err != nil {
+		panic(config.ErrInternal.New().Append(err))
+	}
 }
 
 func (s *StaffUser) getHrAssiant(corpId int64) *qyweixin.AppHr {
diff --git a/server/service/pay.go b/service/pay.go
similarity index 75%
rename from server/service/pay.go
rename to service/pay.go
index c2c3a19..f2d9e0f 100644
--- a/server/service/pay.go
+++ b/service/pay.go
@@ -6,7 +6,6 @@ import (
 	"enterprise/common/dao"
 	"enterprise/common/global"
 	"enterprise/common/model"
-	"enterprise/server/session"
 	"fmt"
 	"git.u8t.cn/open/gosdk/qyweixin"
 	"github.com/gogap/errors"
@@ -24,40 +23,7 @@ func NewPay() *Pay {
 	return &Pay{}
 }
 
-func (p *Pay) AlipayAuth(sess *session.AdminSession, authCode, state string) (string, *model.StaffUser) {
-
-	corp, err := dao.NewCorpDao().GetByHost(sess.GetHeader().Host)
-	session.CheckDBError(err)
-	session.CheckNilError(corp)
-	cli := config.GetAliPayClient("batiao")
-
-	var req alipay.SystemOauthToken
-	req.Code = authCode
-	req.GrantType = "authorization_code"
-	res, err := cli.SystemOauthToken(context.Background(), req)
-	if err != nil {
-		log.Errorf("error :%s", err.Error())
-		panic(config.ErrInternal.New().Append(err))
-	}
-	if !res.IsSuccess() {
-		log.Errorf(goutil.EncodeJSON(res))
-		panic(config.ErrInternal.New().Append(goutil.EncodeJSON(res)))
-	}
-
-	staffUser, err := dao.NewStaffUserDao().Get(cast.ToInt64(state))
-	session.CheckDBError(err)
-	session.CheckNilError(staffUser)
-	payee := staffUser.GetPayee()
-	oldUid := payee.AlipayUid
-	payee.AlipayUid = res.UserId
-	staffUser.Payee = goutil.EncodeJSON(payee)
-	err = dao.NewStaffUserDao().Update(staffUser)
-	session.CheckDBError(err)
-	log.Errorf("staffuser[%d] alipayUid[%s]->alipayUid[%s]", staffUser.Id, oldUid, res.UserId)
-	return res.UserId, staffUser
-}
-
-func (p *Pay) Pay(corp *model.Corp, user *model.StaffUser, title, payType string, amount int64) {
+func (p *Pay) Pay(corp *model.Corp, user *model.StaffUser, title, payType string, amount int64) error {
 	var err error
 	realPayType := ""
 	payee := user.GetPayee()
@@ -82,7 +48,7 @@ func (p *Pay) Pay(corp *model.Corp, user *model.StaffUser, title, payType string
 		message = append(message, fmt.Sprintf("错误信息:%s", err.Error()))
 		global.SendMessage([]string{"jiangyong"}, strings.Join(message, "\n"))
 		log.Errorf("pay req[%s:%d] error :%s", title, amount, err.Error())
-		panic(config.ErrInternal.New().Append(err))
+		return err
 	}
 
 	plog := new(model.StaffPayLog)
@@ -93,6 +59,7 @@ func (p *Pay) Pay(corp *model.Corp, user *model.StaffUser, title, payType string
 	dao.NewStaffPayLogDao().Create(plog)
 
 	global.SendMessage([]string{"jiangyong"}, strings.Join(message, "\n"))
+	return nil
 }
 
 func (p *Pay) payAlipay(corp *model.Corp, user *model.StaffUser, title string, amount int64) error {
diff --git a/worker/staff.go b/worker/staff.go
index 57265f1..ef8e8ba 100644
--- a/worker/staff.go
+++ b/worker/staff.go
@@ -7,7 +7,6 @@ import (
 	"enterprise/service"
 	"fmt"
 	log "github.com/sirupsen/logrus"
-	"github.com/smbrave/goutil"
 	"strings"
 	"time"
 )
@@ -88,13 +87,11 @@ func (s *Staff) SendStaffSalaryBill(corpId int64, month string) {
 			log.Errorf("db error :%s", err.Error())
 			continue
 		}
-		encId := goutil.EncryptID(staffSalary.Id, "@@salary@@")
-		billUrl := fmt.Sprintf("https://e.yubanqy.com/api/staff/salary/bill?id=%s", encId)
 
 		message := make([]string, 0)
 		message = append(message, fmt.Sprintf("【工资单】[%s][%s]", staffUser.Username, month))
 		message = append(message, fmt.Sprintf("实发工资:%.2f", staffSalary.GetRealSalary()))
-		message = append(message, fmt.Sprintf(`<a href="%s">查看明细</a>`, billUrl))
+		message = append(message, fmt.Sprintf(`<a href="%s">查看明细</a>`, staffSalary.GetBillUrl()))
 
 		if err := global.SendMessage([]string{"jiangyong"}, strings.Join(message, "\n")); err != nil {
 			log.Errorf("send message error :%s", err.Error())
@@ -103,6 +100,53 @@ func (s *Staff) SendStaffSalaryBill(corpId int64, month string) {
 	}
 }
 
+func (s *Staff) PayStaffSalary(corpId int64, month string) {
+	staffSalarys, err := dao.NewStaffSalaryDao().QueryAll(corpId, month, model.StaffSalaryStatusWait)
+	if err != nil {
+		log.Errorf("db error :%s", err.Error())
+		return
+	}
+
+	corp, err := dao.NewCorpDao().Get(corpId)
+	if err != nil {
+		log.Errorf("db error :%s", err.Error())
+		return
+	}
+	for _, staffSalary := range staffSalarys {
+		if staffSalary.Salary < 0.1 {
+			continue
+		}
+
+		staffUser, err := dao.NewStaffUserDao().Get(staffSalary.UserId)
+		if err != nil {
+			log.Errorf("db error :%s", err.Error())
+			continue
+		}
+
+		message := make([]string, 0)
+		message = append(message, fmt.Sprintf("【工资发放】[%s]", staffUser.Realname))
+		message = append(message, fmt.Sprintf("实发工资:%.2f", staffSalary.GetRealSalary()))
+		message = append(message, fmt.Sprintf(`<a href="%s">查看明细</a>`, staffSalary.GetBillUrl()))
+
+		if staffUser.Username == "jiangyong" {
+			err = service.NewPay().Pay(corp, staffUser, model.StaffSalaryPaymentAlipay, "", int64(100*staffSalary.GetRealSalary()))
+			if err == nil {
+				staffSalary.Status = model.StaffSalaryStatusPayed
+				message = append(message, "发放成功")
+			} else {
+				staffSalary.SetExtra("pay_error", err.Error())
+				message = append(message, fmt.Sprintf("发动失败:%.2f", err.Error()))
+			}
+			dao.NewStaffSalaryDao().Update(staffSalary)
+		}
+
+		if err := global.SendCorpMessage(staffSalary.CorpId, []string{"jiangyong"}, strings.Join(message, "\n")); err != nil {
+			log.Errorf("send message error :%s", err.Error())
+		}
+
+	}
+}
+
 func (s *Staff) SyncStaffSalary(corpId int64, month string) {
 	if month == "" {
 		month = time.Now().AddDate(0, -1, 0).Format("2006-01")
diff --git a/worker/worker.go b/worker/worker.go
index f578c7a..19a0127 100644
--- a/worker/worker.go
+++ b/worker/worker.go
@@ -51,7 +51,7 @@ func InitCorp1002(cron *gocron.Scheduler) {
 	//10号晚上8点发送工资单
 	cron.Every(1).Month(3).At("22:00").Do(func() {
 		go staff.SendStaffSalaryBill(corpId, time.Now().AddDate(0, -1, 0).Format("200601"))
-		//go staff.SendStaffSalaryBill(1002, time.Now().AddDate(0, -1, 0).Format("200601"))
+		go staff.PayStaffSalary(corpId, time.Now().AddDate(0, -1, 0).Format("200601"))
 	})
 }
 
@@ -92,6 +92,7 @@ func InitCorp1000(cron *gocron.Scheduler) {
 	//10号晚上8点发送工资单
 	cron.Every(1).Month(3).At("22:00").Do(func() {
 		go NewStaff().SendStaffSalaryBill(corpId, time.Now().AddDate(0, -1, 0).Format("200601"))
+		go NewStaff().PayStaffSalary(corpId, time.Now().AddDate(0, -1, 0).Format("200601"))
 	})
 
 }