Ethan преди 5 месеца
родител
ревизия
64c77cb911

+ 3 - 5
app/controller/finance_controller.go

@@ -1,7 +1,6 @@
 package controller
 
 import (
-	"fmt"
 	"github.com/gin-gonic/gin"
 	"github.com/sirupsen/logrus"
 	"youngee_b_api/app/service"
@@ -40,9 +39,8 @@ func (t FinanceController) GetCodeUrl(c *gin.Context) {
 		returnError(c, 40000, "参数错误")
 		return
 	}
-	tradeId := util.GetRandomString(32)
-	fmt.Println("amount:", param.Amount)
-	codeUrl, timeExpire, err := service.RechargeService{}.NativeApiServicePrepay(tradeId, param.Amount)
+	tradeId := util.GenerateDateRelatedUUID(16)
+	codeUrl, timeExpire, err := service.RechargeService{}.NativeApiServicePrepay(param.EnterpriseId, param.SubAccountId, tradeId, param.Amount)
 	if err != nil {
 		logrus.Errorf("[GetCodeUrl] call Show err:%+v\n", err)
 		returnError(c, 40000, err.Error())
@@ -65,7 +63,7 @@ func (t FinanceController) QueryOrderByTradeId(c *gin.Context) {
 		returnError(c, 40000, "参数错误")
 		return
 	}
-	tradeState, err := service.RechargeService{}.QueryOrderByTradeId(param.TradeId)
+	tradeState, err := service.RechargeService{}.QueryOrderByTradeId(param.EnterpriseId, param.SubAccountId, param.TradeId)
 	if err != nil {
 		logrus.Errorf("[QueryOrderByTradeId] call Show err:%+v\n", err)
 		returnError(c, 40000, err.Error())

+ 18 - 1
app/dao/enterprise_dao.go

@@ -24,9 +24,26 @@ func (d EnterpriseDao) GetEnterprise(enterpriseId string) (*entity.Enterprise, e
 
 func (d EnterpriseDao) GetEnterprisePhone(enterpriseId string) (string, error) {
 	var phone string
-	err := Db.Model(&entity.Enterprise{}).Where("enterprise_id = ?", enterpriseId).Select("phone").First(&phone).Error
+	err := Db.Debug().Model(&entity.Enterprise{}).Where("enterprise_id = ?", enterpriseId).Select("phone").First(&phone).Error
 	if err != nil {
 		return "", err
 	}
 	return phone, nil
 }
+
+// 更新账户余额
+func (d EnterpriseDao) UpdateEnterpriseBalance(enterpriseId string, balance float64) (*string, error) {
+	var enterprise entity.Enterprise
+	var err error
+	err = Db.Debug().Model(&entity.Enterprise{}).Where("enterprise_id = ?", enterpriseId).First(&enterprise).Error
+	if err != nil {
+		return nil, err
+	}
+	enterprise.Balance += balance
+	enterprise.AvailableBalance += balance
+	err = Db.Debug().Model(&entity.Enterprise{}).Where("enterprise_id = ?", enterpriseId).Updates(enterprise).Error
+	if err != nil {
+		return nil, err
+	}
+	return &enterpriseId, nil
+}

+ 33 - 1
app/dao/recharge_record_dao.go

@@ -1,6 +1,7 @@
 package dao
 
 import (
+	"time"
 	"youngee_b_api/app/entity"
 	"youngee_b_api/app/vo"
 )
@@ -15,7 +16,7 @@ func (d RechargeRecordDao) Insert(rechargeRecord *entity.RechargeRecord) error {
 	return nil
 }
 
-// 获取指定企业id的充值金额、确认中金额
+// 获取指定企业id的累计充值金额、充值确认中金额
 func (d RechargeRecordDao) GetRechargeAmount(enterpriseId string, status int64) (float64, error) {
 	var totalAmount float64
 	query := Db.Debug().Model(&entity.RechargeRecord{})
@@ -48,3 +49,34 @@ func (d RechargeRecordDao) RechargeInfoList(param *vo.RechargeParam) ([]entity.R
 
 	return rechargeRecords, total, nil
 }
+
+// 更新充值状态
+func (d RechargeRecordDao) UpdateRechargeStatus(enterpriseId string, subAccountId int64, status int64, t time.Time) error {
+	rechargeRecord := entity.RechargeRecord{
+		Status: status,
+	}
+	if status == 2 {
+		rechargeRecord.InvoiceStatus = 1
+		rechargeRecord.ConfirmAt = t
+	}
+	if status == 3 {
+		rechargeRecord.FailReason = "支付失败"
+		rechargeRecord.RefuseAt = t
+	}
+	err = Db.Debug().Model(&entity.RechargeRecord{}).Where("enterprise_id = ? AND sub_account_id = ?", enterpriseId, subAccountId).Updates(rechargeRecord).Error
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// 更新所有充值记录中微信支付超时的记录
+func (d RechargeRecordDao) UpdateRechargeFailedList() error {
+	now := time.Now()
+	err := Db.Debug().Model(&entity.RechargeRecord{}).Where("recharge_method = ? AND status = ? AND refuse_at < ?", 2, 1, now).
+		Updates(map[string]interface{}{"status": 3, "fail_reason": "微信支付失败"}).Error
+	if err != nil {
+		return err
+	}
+	return nil
+}

+ 3 - 2
app/entity/recharge_record.go

@@ -3,8 +3,9 @@ package entity
 import "time"
 
 type RechargeRecord struct {
-	RechargeID         string    `gorm:"column:recharge_id;primary_key"` // 充值订单ID
-	EnterpriseID       string    `gorm:"column:enterprise_id;NOT NULL"`  // 企业id
+	ID                 int64     `gorm:"column:id;primary_key;column:id"`
+	RechargeID         string    `gorm:"column:recharge_id;unique_key"` // 充值订单ID
+	EnterpriseID       string    `gorm:"column:enterprise_id;NOT NULL"` // 企业id
 	SubAccountId       int64     `gorm:"column:sub_account_id;NOT NULL"`
 	RechargeAmount     float64   `gorm:"column:recharge_amount;NOT NULL"`      // 充值金额
 	TransferVoucherUrl string    `gorm:"column:transfer_voucher_url;NOT NULL"` // 转账凭证图片链接

+ 2 - 2
app/schedule/auto_task.go → app/schedule/auto_task1.go

@@ -10,10 +10,10 @@ import (
 	"youngee_b_api/app/entity"
 )
 
-func AutoTask() error {
+func AutoTask1() error {
 	// 新建一个定时任务对象
 	crontab := cron.New(cron.WithSeconds()) // 精确到秒
-	spec := "0 0 */5 * * ?"                 //cron表达式,每10h一次
+	spec := "0 */5 * * * ?"                 //cron表达式,每5h一次
 	// "0 0 12 * * ?" 每天中午12点执行
 
 	// 添加定时任务

+ 33 - 0
app/schedule/auto_task2.go

@@ -0,0 +1,33 @@
+package schedule
+
+import (
+	"github.com/robfig/cron/v3"
+	"log"
+	"time"
+	"youngee_b_api/app/dao"
+)
+
+func AutoTask2() error {
+	// 新建一个定时任务对象
+	crontab := cron.New(cron.WithSeconds()) // 精确到秒
+	spec := "0 */2 * * * ?"                 //cron表达式
+
+	// 定时任务  检查微信支付是否充值成功
+	_, err1 := crontab.AddFunc(spec, AutoCheckWXRechargeTask)
+	if err1 != nil {
+		return err1
+	}
+
+	// 启动定时器
+	crontab.Start()
+	// 定时任务是另起协程执行的,这里使用 select 简单阻塞.需要根据实际情况进行控制
+	//select {} //阻塞主线程停止
+	return nil
+}
+
+// 定时任务  检查微信支付是否充值成功
+func AutoCheckWXRechargeTask() {
+	log.Println("AutoCheckWXRechargeTask running Start, Time :", time.Now())
+	_ = dao.RechargeRecordDao{}.UpdateRechargeFailedList()
+	log.Println("AutoCheckWXRechargeTask running End, Time :", time.Now())
+}

+ 1 - 1
app/service/invoice_service.go

@@ -71,7 +71,7 @@ func (s InvoiceService) GetInvoiceDefault(param *vo.InvoiceDefaultParam) (*vo.Re
 // 确认开票
 func (s InvoiceService) BillInvoice(param *vo.InvoiceBillParam) (*string, error) {
 	var err error
-	billingId := util.GenerateDateRelatedUUID()
+	billingId := util.GenerateDateRelatedUUID(16)
 	taskIds := param.TaskIds
 	// 将二维数组转换为 JSON 字符串
 	jsonData, _ := json.Marshal(taskIds)

+ 35 - 7
app/service/recharge_service.go

@@ -30,7 +30,7 @@ func (s RechargeService) TransferToPublic(param *vo.RechargeTransferParam) (*str
 	//	rechargeId = util.MakeRechargeId(strconv.FormatInt(param.SubAccountId, 10))
 	//	phone, _ = dao.SubAccountDao{}.GetSubAccountPhone(param.SubAccountId)
 	//}
-	rechargeId = util.GenerateDateRelatedUUID()
+	rechargeId = util.GenerateDateRelatedUUID(16)
 	phone, _ = dao.EnterpriseDao{}.GetEnterprisePhone(param.EnterpriseId)
 	rechargeRecord := entity.RechargeRecord{
 		RechargeID:         rechargeId,
@@ -41,7 +41,6 @@ func (s RechargeService) TransferToPublic(param *vo.RechargeTransferParam) (*str
 		Phone:              phone,
 		RechargeMethod:     1,
 		Status:             1,
-		InvoiceStatus:      1,
 		CommitAt:           time.Now(),
 	}
 	err := dao.RechargeRecordDao{}.Insert(&rechargeRecord)
@@ -52,13 +51,12 @@ func (s RechargeService) TransferToPublic(param *vo.RechargeTransferParam) (*str
 }
 
 // 获取微信支付CodeUrl
-func (s RechargeService) NativeApiServicePrepay(tradeId string, amount int64) (string, *time.Time, error) {
+func (s RechargeService) NativeApiServicePrepay(enterpriseId string, subAccountId int64, tradeId string, amount int64) (string, *time.Time, error) {
 	var (
 		mchID                      string = "1615933939"                               // 商户号
 		mchCertificateSerialNumber string = "33DDFEC51BF5412F663B9B56510FD567B625FC68" // 商户证书序列号
 		mchAPIv3Key                string = "V10987654321younggee12345678910V"         // 商户APIv3密钥,用于加密和解密平台证书
 	)
-	fmt.Println("充值的金额为:", amount)
 
 	// 使用 utils 提供的函数从本地文件中加载商户私钥
 	mchPrivateKey, err := utils.LoadPrivateKeyWithPath("./apiclient_key.pem") // 商户私钥,用于生成请求的签名
@@ -79,7 +77,7 @@ func (s RechargeService) NativeApiServicePrepay(tradeId string, amount int64) (s
 	// 采用 Native 支付方式
 	svc := native.NativeApiService{Client: client}
 	// 发送请求
-	timeExpire := time.Now().Add(10 * time.Minute)
+	timeExpire := time.Now().Add(5 * time.Minute)
 	resp, result, err := svc.Prepay(ctx,
 		native.PrepayRequest{
 			Appid:         core.String("wxac396a3be7a16844"),
@@ -106,12 +104,31 @@ func (s RechargeService) NativeApiServicePrepay(tradeId string, amount int64) (s
 		log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
 		log.Println("codeUrl:", *resp.CodeUrl)
 	}
+
+	// 生成充值记录
+	phone, _ := dao.EnterpriseDao{}.GetEnterprisePhone(enterpriseId)
+	rechargeRecord := entity.RechargeRecord{
+		RechargeID:     tradeId,
+		EnterpriseID:   enterpriseId,
+		SubAccountId:   subAccountId,
+		RechargeAmount: float64(amount) / 100,
+		Phone:          phone,
+		RechargeMethod: 2,
+		Status:         1,
+		CommitAt:       time.Now(),
+		RefuseAt:       timeExpire,
+	}
+	err = dao.RechargeRecordDao{}.Insert(&rechargeRecord)
+	if err != nil {
+		return "", nil, err
+	}
+
 	return *resp.CodeUrl, &timeExpire, nil
 }
 
 // 根据交易id查询微信是否扫码付款
 // https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_2.shtml
-func (s RechargeService) QueryOrderByTradeId(tradeId string) (tradeState string, err error) {
+func (s RechargeService) QueryOrderByTradeId(enterpriseId string, subAccountId int64, tradeId string) (tradeState string, err error) {
 	var (
 		mchID                      string = "1615933939"                               // 商户号
 		mchCertificateSerialNumber string = "33DDFEC51BF5412F663B9B56510FD567B625FC68" // 商户证书序列号
@@ -150,7 +167,18 @@ func (s RechargeService) QueryOrderByTradeId(tradeId string) (tradeState string,
 		// 处理返回结果
 		log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
 	}
-	fmt.Printf("支付状态 %+v\n", *resp.TradeState)
+
+	// 更新充值记录/账户金额相关信息
+	if "SUCCESS" == *resp.TradeState {
+		payTime := resp.SuccessTime
+		t, _ := time.Parse("2006-01-02 15:04:05", *payTime)
+		err = dao.RechargeRecordDao{}.UpdateRechargeStatus(enterpriseId, subAccountId, 2, t)
+		amount := float64(*resp.Amount.Total) / 100
+		_, err = dao.EnterpriseDao{}.UpdateEnterpriseBalance(enterpriseId, amount)
+	} else if "CLOSED" == *resp.TradeState {
+		err = dao.RechargeRecordDao{}.UpdateRechargeStatus(enterpriseId, subAccountId, 3, time.Now())
+	}
+
 	return *resp.TradeState, nil
 }
 

+ 2 - 2
app/util/uuid.go

@@ -90,8 +90,8 @@ func MakeRechargeId(enterpriseID string) string {
 	return rechargeIdPrefix + last
 }
 
-func GenerateDateRelatedUUID() string {
+func GenerateDateRelatedUUID(num int64) string {
 	date := time.Now().Format("20060102") // 获取当前日期
 	u := uuid.New()
-	return date + u.String()[:8]
+	return date + u.String()[:(num-8)]
 }

+ 3 - 1
app/vo/pay_wx_param.go

@@ -7,7 +7,9 @@ type GetCodeUrlParam struct {
 }
 
 type QueryOrderByTradeIdParam struct {
-	TradeId string `json:"trade_id"`
+	EnterpriseId string `json:"enterprise_id"` // 企业id
+	SubAccountId int64  `json:"sub_account_id"`
+	TradeId      string `json:"trade_id"`
 }
 
 type ReCodeUrl struct {

+ 5 - 4
route/init.go

@@ -231,10 +231,11 @@ func InitRoute(r *gin.Engine) {
 		finance.POST("/recharge/transferToPublic", controller.FinanceController{}.TransferToPublic)  // 充值管理——对公转账
 		finance.POST("/pay/getCodeUrl", controller.FinanceController{}.GetCodeUrl)                   // 获取微信支付codeURL
 		finance.POST("/pay/queryOrderByTradeId", controller.FinanceController{}.QueryOrderByTradeId) // 根据交易id查询微信是否扫码付款
-		finance.POST("/balance/show", controller.FinanceController{}.ShowBalance)                    // 余额管理——总金额、可用余额、冻结金额
-		finance.POST("/balance/frozen/info", controller.FinanceController{}.FrozenInfoList)          // 余额管理——冻结记录
-		finance.POST("/recharge/show", controller.FinanceController{}.ShowRecharge)                  // 充值管理——累计充值金额、确认中金额
-		finance.POST("/recharge/info", controller.FinanceController{}.RechargeInfoList)              // 充值管理——充值记录
+		// 微信支付充值成功上报(待开会确定超时未支付算不算充值失败)
+		finance.POST("/balance/show", controller.FinanceController{}.ShowBalance)           // 余额管理——总金额、可用余额、冻结金额
+		finance.POST("/balance/frozen/info", controller.FinanceController{}.FrozenInfoList) // 余额管理——冻结记录
+		finance.POST("/recharge/show", controller.FinanceController{}.ShowRecharge)         // 充值管理——累计充值金额、确认中金额
+		finance.POST("/recharge/info", controller.FinanceController{}.RechargeInfoList)     // 充值管理——充值记录
 		// YG官方汇款账号
 		finance.POST("/invoice/default/update", controller.FinanceController{}.UpdateInvoiceDefault) // 设置默认开票抬头
 		finance.POST("/invoice/default/get", controller.FinanceController{}.GetInvoiceDefault)       // 获取默认开票抬头