add count easypay

This commit is contained in:
2026-01-09 14:04:33 +08:00
parent f079980608
commit 2ca14de27e
14 changed files with 211 additions and 62 deletions

View File

@@ -19,17 +19,126 @@ import (
// EasyPayService 易支付服务
type EasyPayService struct {
config config.EasyPayConfig
client *http.Client
config config.EasyPayConfig
client *http.Client
orderModel model.OrderModel // 订单模型,用于次数轮询模式查询用户订单数量
}
// getSelectedCID 获取当前应该使用的渠道ID
// ctx: 上下文用于次数轮询模式时访问Redis
// userID: 用户ID用于次数轮询模式时记录用户使用的渠道
func (e *EasyPayService) getSelectedCID(ctx context.Context, userID string) string {
// 如果没有配置 CID返回空字符串
if len(e.config.CIDs) == 0 {
return ""
}
// 如果只有一个渠道,直接返回
if len(e.config.CIDs) == 1 {
return e.config.CIDs[0]
}
// 根据轮询模式选择策略
rotateMode := e.config.RotateMode
if rotateMode == "" {
rotateMode = "day" // 默认天数轮询
}
switch rotateMode {
case "count":
// 次数轮询模式:按用户订单次数轮询
return e.selectCIDByCount(ctx, userID)
case "day":
// 天数轮询模式:按时间轮询
return e.selectCIDByRotation()
default:
// 默认使用天数轮询
logx.Infof("未知的轮询模式: %s使用默认天数轮询", rotateMode)
return e.selectCIDByRotation()
}
}
// selectCIDByRotation 按时间轮询策略选择CID
func (e *EasyPayService) selectCIDByRotation() string {
if len(e.config.CIDs) == 0 {
return ""
}
// 如果只有一个,直接返回
if len(e.config.CIDs) == 1 {
return e.config.CIDs[0]
}
// 获取轮询天数默认3天
rotateDays := e.config.RotateDays
if rotateDays <= 0 {
rotateDays = 3
}
// 计算从某个基准日期比如2020-01-01开始的天数
baseDate := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
now := time.Now()
daysSinceBase := int(now.Sub(baseDate).Hours() / 24)
// 按轮询天数计算当前应该使用的索引
rotationIndex := (daysSinceBase / rotateDays) % len(e.config.CIDs)
selectedCID := e.config.CIDs[rotationIndex]
logx.Infof("易支付渠道天数轮询选择: 总渠道数=%d, 轮询天数=%d, 当前索引=%d, 选择渠道=%s",
len(e.config.CIDs), rotateDays, rotationIndex, selectedCID)
return selectedCID
}
// selectCIDByCount 按次数轮询策略选择CID针对用户
func (e *EasyPayService) selectCIDByCount(ctx context.Context, userID string) string {
if len(e.config.CIDs) == 0 {
return ""
}
// 如果只有一个,直接返回
if len(e.config.CIDs) == 1 {
return e.config.CIDs[0]
}
// 如果没有用户ID回退到天数轮询
if userID == "" {
logx.Infof("次数轮询模式但用户ID为空回退到天数轮询")
return e.selectCIDByRotation()
}
// 查询该用户的易支付订单数量
orderCount := int64(0)
if e.orderModel != nil {
builder := e.orderModel.SelectBuilder().
Where("user_id = ?", userID).
Where("payment_platform = ?", "easypay_alipay")
count, err := e.orderModel.FindCount(ctx, builder, "id")
if err != nil {
logx.Errorf("查询用户易支付订单数量失败: %v使用索引0", err)
} else {
orderCount = count
}
}
// 根据订单数量计算应该使用的渠道索引订单数量从0开始所以第0个订单用索引0第1个订单用索引1以此类推
channelIndex := int(orderCount) % len(e.config.CIDs)
selectedCID := e.config.CIDs[channelIndex]
logx.Infof("易支付渠道次数轮询选择: 用户ID=%s, 总渠道数=%d, 用户订单数=%d, 选择索引=%d, 选择渠道=%s",
userID, len(e.config.CIDs), orderCount, channelIndex, selectedCID)
return selectedCID
}
// NewEasyPayService 创建易支付服务实例
func NewEasyPayService(c config.Config) *EasyPayService {
func NewEasyPayService(c config.Config, orderModel model.OrderModel) *EasyPayService {
return &EasyPayService{
config: c.EasyPay,
client: &http.Client{
Timeout: 30 * time.Second,
},
orderModel: orderModel,
}
}
@@ -189,7 +298,7 @@ func (e *EasyPayService) verifySign(params map[string]string, sign string) bool
}
// CreateEasyPayH5Order 创建易支付H5订单页面跳转方式
func (e *EasyPayService) CreateEasyPayH5Order(amount float64, subject string, outTradeNo string) (string, error) {
func (e *EasyPayService) CreateEasyPayH5Order(ctx context.Context, amount float64, subject string, outTradeNo string, userID string) (string, error) {
// 格式化金额,保留两位小数
moneyStr := fmt.Sprintf("%.2f", amount)
@@ -203,9 +312,9 @@ func (e *EasyPayService) CreateEasyPayH5Order(amount float64, subject string, ou
"return_url": e.config.ReturnUrl,
"sign_type": "MD5",
}
// 如果配置了渠道ID则添加
if e.config.CID != "" {
params["cid"] = e.config.CID
// 获取并添加渠道ID
if cid := e.getSelectedCID(ctx, userID); cid != "" {
params["cid"] = cid
}
// 生成签名
@@ -226,7 +335,7 @@ func (e *EasyPayService) CreateEasyPayH5Order(amount float64, subject string, ou
}
// CreateEasyPayAppOrder 创建易支付APP订单API方式
func (e *EasyPayService) CreateEasyPayAppOrder(ctx context.Context, amount float64, subject string, outTradeNo string, clientIP string) (string, error) {
func (e *EasyPayService) CreateEasyPayAppOrder(ctx context.Context, amount float64, subject string, outTradeNo string, clientIP string, userID string) (string, error) {
// 格式化金额,保留两位小数
moneyStr := fmt.Sprintf("%.2f", amount)
@@ -241,9 +350,9 @@ func (e *EasyPayService) CreateEasyPayAppOrder(ctx context.Context, amount float
"device": "pc",
"sign_type": "MD5",
}
// 如果配置了渠道ID则添加
if e.config.CID != "" {
params["cid"] = e.config.CID
// 获取并添加渠道ID
if cid := e.getSelectedCID(ctx, userID); cid != "" {
params["cid"] = cid
}
// 生成签名
@@ -302,14 +411,25 @@ func (e *EasyPayService) CreateEasyPayAppOrder(ctx context.Context, amount float
return "", fmt.Errorf("未获取到支付链接")
}
// CreateEasyPayOrderResult 易支付订单创建结果
type CreateEasyPayOrderResult struct {
PayURL string // 支付URL
CID string // 使用的渠道ID
}
// CreateEasyPayOrder 根据平台类型创建易支付订单
func (e *EasyPayService) CreateEasyPayOrder(ctx context.Context, amount float64, subject string, outTradeNo string) (string, error) {
func (e *EasyPayService) CreateEasyPayOrder(ctx context.Context, amount float64, subject string, outTradeNo string, userID string) (*CreateEasyPayOrderResult, error) {
// 获取选中的渠道ID
selectedCID := e.getSelectedCID(ctx, userID)
// 根据 ctx 中的 platform 判断平台
platform, platformOk := ctx.Value("platform").(string)
if !platformOk {
return "", fmt.Errorf("无效的支付平台")
return nil, fmt.Errorf("无效的支付平台")
}
var payURL string
var err error
switch platform {
case model.PlatformApp:
// APP平台使用API方式
@@ -317,13 +437,22 @@ func (e *EasyPayService) CreateEasyPayOrder(ctx context.Context, amount float64,
if ip, ok := ctx.Value("client_ip").(string); ok {
clientIP = ip
}
return e.CreateEasyPayAppOrder(ctx, amount, subject, outTradeNo, clientIP)
payURL, err = e.CreateEasyPayAppOrder(ctx, amount, subject, outTradeNo, clientIP, userID)
case model.PlatformH5:
// H5平台使用页面跳转方式
return e.CreateEasyPayH5Order(amount, subject, outTradeNo)
payURL, err = e.CreateEasyPayH5Order(ctx, amount, subject, outTradeNo, userID)
default:
return "", fmt.Errorf("不支持的支付平台: %s", platform)
return nil, fmt.Errorf("不支持的支付平台: %s", platform)
}
if err != nil {
return nil, err
}
return &CreateEasyPayOrderResult{
PayURL: payURL,
CID: selectedCID,
}, nil
}
// HandleEasyPayNotification 处理易支付回调通知