add count easypay
This commit is contained in:
@@ -87,6 +87,8 @@ EasyPay:
|
|||||||
ApiURL: "https://zpayz.cn/"
|
ApiURL: "https://zpayz.cn/"
|
||||||
PID: "2025123009590455"
|
PID: "2025123009590455"
|
||||||
PKEY: "f61pwaOj93lYpesM82ZnPAVwFojuSL7F"
|
PKEY: "f61pwaOj93lYpesM82ZnPAVwFojuSL7F"
|
||||||
CID: "12200"
|
CIDs: ["12200"] # 支付渠道ID数组,可配置一个或多个,多个时会按RotateDays轮询
|
||||||
NotifyUrl: "https://6m4685017o.goho.co/api/v1/pay/easypay/callback"
|
# CIDs: ["12200", "12201", "12202"] # 多个渠道示例,会按RotateDays天数轮询
|
||||||
ReturnUrl: "http://localhost:5678/payment/result"
|
RotateDays: 3 # 渠道轮询天数,默认3天(仅在配置了多个CIDs时生效)
|
||||||
|
NotifyUrl: "https://www.dsjcq168.cn/api/v1/pay/easypay/callback"
|
||||||
|
ReturnUrl: "https://www.dsjcq168.cn/payment/result"
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ EasyPay:
|
|||||||
ApiURL: "https://zpayz.cn/"
|
ApiURL: "https://zpayz.cn/"
|
||||||
PID: "2025123009590455"
|
PID: "2025123009590455"
|
||||||
PKEY: "f61pwaOj93lYpesM82ZnPAVwFojuSL7F"
|
PKEY: "f61pwaOj93lYpesM82ZnPAVwFojuSL7F"
|
||||||
CID: "12200"
|
CIDs: ["12200", "12303"] # 支付渠道ID数组,可配置一个或多个
|
||||||
|
RotateMode: "count" # 轮询模式:day(天数轮询)或 count(次数轮询),默认count
|
||||||
|
RotateDays: 3 # 渠道轮询天数,默认3天(仅在RotateMode=day时生效)
|
||||||
NotifyUrl: "https://www.dsjcq168.cn/api/v1/pay/easypay/callback"
|
NotifyUrl: "https://www.dsjcq168.cn/api/v1/pay/easypay/callback"
|
||||||
ReturnUrl: "https://www.dsjcq168.cn/payment/result"
|
ReturnUrl: "https://www.dsjcq168.cn/payment/result"
|
||||||
|
|||||||
@@ -125,11 +125,13 @@ type PromotionConfig struct {
|
|||||||
|
|
||||||
// EasyPayConfig 易支付配置
|
// EasyPayConfig 易支付配置
|
||||||
type EasyPayConfig struct {
|
type EasyPayConfig struct {
|
||||||
Enabled bool // 是否启用易支付
|
Enabled bool // 是否启用易支付
|
||||||
ApiURL string // 接口地址
|
ApiURL string // 接口地址
|
||||||
PID string // 商户ID
|
PID string // 商户ID
|
||||||
PKEY string // 商户密钥
|
PKEY string // 商户密钥
|
||||||
CID string // 支付渠道ID
|
CIDs []string // 支付渠道ID数组(可配置一个或多个)
|
||||||
NotifyUrl string // 异步通知地址
|
RotateMode string // 轮询模式:day(天数轮询)或 count(次数轮询),默认day
|
||||||
ReturnUrl string // 页面跳转地址
|
RotateDays int // 渠道轮询天数(默认3天,仅在RotateMode=day时生效)
|
||||||
|
NotifyUrl string // 异步通知地址
|
||||||
|
ReturnUrl string // 页面跳转地址
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
"jnc-server/app/main/api/internal/svc"
|
"jnc-server/app/main/api/internal/svc"
|
||||||
"jnc-server/app/main/api/internal/types"
|
"jnc-server/app/main/api/internal/types"
|
||||||
"jnc-server/common/globalkey"
|
|
||||||
"jnc-server/pkg/lzkit/crypto"
|
"jnc-server/pkg/lzkit/crypto"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -66,7 +65,6 @@ func (l *AdminGetAgentRankingLogic) AdminGetAgentRanking(req *types.AdminGetAgen
|
|||||||
func (l *AdminGetAgentRankingLogic) queryCommissionRanking(limit int) ([]types.AgentRankingItem, error) {
|
func (l *AdminGetAgentRankingLogic) queryCommissionRanking(limit int) ([]types.AgentRankingItem, error) {
|
||||||
// 1. Query all commissions
|
// 1. Query all commissions
|
||||||
builder := l.svcCtx.AgentCommissionModel.SelectBuilder()
|
builder := l.svcCtx.AgentCommissionModel.SelectBuilder()
|
||||||
builder = builder.Where("del_state = ?", globalkey.DelStateNo)
|
|
||||||
|
|
||||||
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, builder, "")
|
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, builder, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -111,7 +109,7 @@ func (l *AdminGetAgentRankingLogic) queryCommissionRanking(limit int) ([]types.A
|
|||||||
}
|
}
|
||||||
|
|
||||||
agents, err := l.svcCtx.AgentModel.FindAll(l.ctx,
|
agents, err := l.svcCtx.AgentModel.FindAll(l.ctx,
|
||||||
l.svcCtx.AgentModel.SelectBuilder().Where("del_state = ?", globalkey.DelStateNo), "")
|
l.svcCtx.AgentModel.SelectBuilder(), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -162,7 +160,6 @@ func (l *AdminGetAgentRankingLogic) queryCommissionRanking(limit int) ([]types.A
|
|||||||
func (l *AdminGetAgentRankingLogic) queryOrdersRanking(limit int) ([]types.AgentRankingItem, error) {
|
func (l *AdminGetAgentRankingLogic) queryOrdersRanking(limit int) ([]types.AgentRankingItem, error) {
|
||||||
// 1. Query all orders
|
// 1. Query all orders
|
||||||
builder := l.svcCtx.AgentOrderModel.SelectBuilder()
|
builder := l.svcCtx.AgentOrderModel.SelectBuilder()
|
||||||
builder = builder.Where("del_state = ?", globalkey.DelStateNo)
|
|
||||||
|
|
||||||
orders, err := l.svcCtx.AgentOrderModel.FindAll(l.ctx, builder, "")
|
orders, err := l.svcCtx.AgentOrderModel.FindAll(l.ctx, builder, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -207,7 +204,7 @@ func (l *AdminGetAgentRankingLogic) queryOrdersRanking(limit int) ([]types.Agent
|
|||||||
}
|
}
|
||||||
|
|
||||||
agents, err := l.svcCtx.AgentModel.FindAll(l.ctx,
|
agents, err := l.svcCtx.AgentModel.FindAll(l.ctx,
|
||||||
l.svcCtx.AgentModel.SelectBuilder().Where("del_state = ?", globalkey.DelStateNo), "")
|
l.svcCtx.AgentModel.SelectBuilder(), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"jnc-server/app/main/api/internal/svc"
|
"jnc-server/app/main/api/internal/svc"
|
||||||
"jnc-server/app/main/api/internal/types"
|
"jnc-server/app/main/api/internal/types"
|
||||||
"jnc-server/app/main/model"
|
"jnc-server/app/main/model"
|
||||||
"jnc-server/common/globalkey"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
@@ -29,7 +28,6 @@ func NewAdminGetProductDistributionLogic(ctx context.Context, svcCtx *svc.Servic
|
|||||||
func (l *AdminGetProductDistributionLogic) AdminGetProductDistribution() (resp *types.AdminGetProductDistributionResp, err error) {
|
func (l *AdminGetProductDistributionLogic) AdminGetProductDistribution() (resp *types.AdminGetProductDistributionResp, err error) {
|
||||||
// 1. Query all commissions
|
// 1. Query all commissions
|
||||||
builder := l.svcCtx.AgentCommissionModel.SelectBuilder()
|
builder := l.svcCtx.AgentCommissionModel.SelectBuilder()
|
||||||
builder = builder.Where("del_state = ?", globalkey.DelStateNo)
|
|
||||||
|
|
||||||
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, builder, "")
|
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, builder, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -50,7 +48,7 @@ func (l *AdminGetProductDistributionLogic) AdminGetProductDistribution() (resp *
|
|||||||
var products []*model.Product
|
var products []*model.Product
|
||||||
if len(productIds) > 0 {
|
if len(productIds) > 0 {
|
||||||
products, err = l.svcCtx.ProductModel.FindAll(l.ctx,
|
products, err = l.svcCtx.ProductModel.FindAll(l.ctx,
|
||||||
l.svcCtx.ProductModel.SelectBuilder().Where("del_state = ?", globalkey.DelStateNo), "")
|
l.svcCtx.ProductModel.SelectBuilder(), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package admin_agent
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"jnc-server/common/globalkey"
|
|
||||||
"jnc-server/common/xerr"
|
"jnc-server/common/xerr"
|
||||||
|
|
||||||
"github.com/Masterminds/squirrel"
|
"github.com/Masterminds/squirrel"
|
||||||
@@ -29,8 +28,7 @@ func NewAdminGetAgentOrderListLogic(ctx context.Context, svcCtx *svc.ServiceCont
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *AdminGetAgentOrderListLogic) AdminGetAgentOrderList(req *types.AdminGetAgentOrderListReq) (resp *types.AdminGetAgentOrderListResp, err error) {
|
func (l *AdminGetAgentOrderListLogic) AdminGetAgentOrderList(req *types.AdminGetAgentOrderListReq) (resp *types.AdminGetAgentOrderListResp, err error) {
|
||||||
builder := l.svcCtx.AgentOrderModel.SelectBuilder().
|
builder := l.svcCtx.AgentOrderModel.SelectBuilder()
|
||||||
Where("del_state = ?", globalkey.DelStateNo)
|
|
||||||
|
|
||||||
if req.AgentId != nil {
|
if req.AgentId != nil {
|
||||||
builder = builder.Where("agent_id = ?", *req.AgentId)
|
builder = builder.Where("agent_id = ?", *req.AgentId)
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"jnc-server/app/main/model"
|
"jnc-server/app/main/model"
|
||||||
"jnc-server/common/globalkey"
|
|
||||||
"jnc-server/common/xerr"
|
"jnc-server/common/xerr"
|
||||||
"jnc-server/pkg/lzkit/crypto"
|
"jnc-server/pkg/lzkit/crypto"
|
||||||
|
|
||||||
@@ -188,8 +187,7 @@ func contains(str, substr string) bool {
|
|||||||
|
|
||||||
// queryOrders 查询订单列表
|
// queryOrders 查询订单列表
|
||||||
func (l *AdminGetAgentOrdersListLogic) queryOrders(req *types.AdminGetAgentOrdersListReq) ([]*model.Order, int64, error) {
|
func (l *AdminGetAgentOrdersListLogic) queryOrders(req *types.AdminGetAgentOrdersListReq) ([]*model.Order, int64, error) {
|
||||||
builder := l.svcCtx.OrderModel.SelectBuilder().
|
builder := l.svcCtx.OrderModel.SelectBuilder()
|
||||||
Where("`del_state` = ?", globalkey.DelStateNo)
|
|
||||||
|
|
||||||
// 订单筛选
|
// 订单筛选
|
||||||
if req.OrderNo != nil && *req.OrderNo != "" {
|
if req.OrderNo != nil && *req.OrderNo != "" {
|
||||||
@@ -275,7 +273,7 @@ func (l *AdminGetAgentOrdersListLogic) queryCommissionsByOrderIds(orderIds []str
|
|||||||
|
|
||||||
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx,
|
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx,
|
||||||
l.svcCtx.AgentCommissionModel.SelectBuilder().
|
l.svcCtx.AgentCommissionModel.SelectBuilder().
|
||||||
Where(fmt.Sprintf("`order_id` IN (%s) AND `del_state` = ?", inClause), append(stringsToInterfaces(orderIds), globalkey.DelStateNo)...),
|
Where(fmt.Sprintf("`order_id` IN (%s)", inClause), stringsToInterfaces(orderIds)...),
|
||||||
"")
|
"")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -319,7 +317,7 @@ func (l *AdminGetAgentOrdersListLogic) queryAgentsByAgentIds(agentIds []string)
|
|||||||
|
|
||||||
agents, err := l.svcCtx.AgentModel.FindAll(l.ctx,
|
agents, err := l.svcCtx.AgentModel.FindAll(l.ctx,
|
||||||
l.svcCtx.AgentModel.SelectBuilder().
|
l.svcCtx.AgentModel.SelectBuilder().
|
||||||
Where(fmt.Sprintf("`id` IN (%s) AND `del_state` = ?", inClause), append(stringsToInterfaces(ids), globalkey.DelStateNo)...),
|
Where(fmt.Sprintf("`id` IN (%s)", inClause), stringsToInterfaces(ids)...),
|
||||||
"")
|
"")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -363,7 +361,7 @@ func (l *AdminGetAgentOrdersListLogic) queryUsersByUserIds(userIds []string) map
|
|||||||
|
|
||||||
users, err := l.svcCtx.UserModel.FindAll(l.ctx,
|
users, err := l.svcCtx.UserModel.FindAll(l.ctx,
|
||||||
l.svcCtx.UserModel.SelectBuilder().
|
l.svcCtx.UserModel.SelectBuilder().
|
||||||
Where(fmt.Sprintf("`id` IN (%s) AND `del_state` = ?", inClause), append(stringsToInterfaces(ids), globalkey.DelStateNo)...),
|
Where(fmt.Sprintf("`id` IN (%s)", inClause), stringsToInterfaces(ids)...),
|
||||||
"")
|
"")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -407,7 +405,7 @@ func (l *AdminGetAgentOrdersListLogic) queryProductsByProductIds(productIds []st
|
|||||||
|
|
||||||
products, err := l.svcCtx.ProductModel.FindAll(l.ctx,
|
products, err := l.svcCtx.ProductModel.FindAll(l.ctx,
|
||||||
l.svcCtx.ProductModel.SelectBuilder().
|
l.svcCtx.ProductModel.SelectBuilder().
|
||||||
Where(fmt.Sprintf("`id` IN (%s) AND `del_state` = ?", inClause), append(stringsToInterfaces(ids), globalkey.DelStateNo)...),
|
Where(fmt.Sprintf("`id` IN (%s)", inClause), stringsToInterfaces(ids)...),
|
||||||
"")
|
"")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -436,7 +434,7 @@ func (l *AdminGetAgentOrdersListLogic) queryQueriesByOrderIds(orderIds []string)
|
|||||||
|
|
||||||
queries, err := l.svcCtx.QueryModel.FindAll(l.ctx,
|
queries, err := l.svcCtx.QueryModel.FindAll(l.ctx,
|
||||||
l.svcCtx.QueryModel.SelectBuilder().
|
l.svcCtx.QueryModel.SelectBuilder().
|
||||||
Where(fmt.Sprintf("`order_id` IN (%s) AND `del_state` = ?", inClause), append(stringsToInterfaces(orderIds), globalkey.DelStateNo)...),
|
Where(fmt.Sprintf("`order_id` IN (%s)", inClause), stringsToInterfaces(orderIds)...),
|
||||||
"")
|
"")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package admin_agent
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"jnc-server/common/globalkey"
|
|
||||||
"jnc-server/common/xerr"
|
"jnc-server/common/xerr"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -28,8 +27,7 @@ func NewAdminGetAgentProductConfigListLogic(ctx context.Context, svcCtx *svc.Ser
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *AdminGetAgentProductConfigListLogic) AdminGetAgentProductConfigList(req *types.AdminGetAgentProductConfigListReq) (resp *types.AdminGetAgentProductConfigListResp, err error) {
|
func (l *AdminGetAgentProductConfigListLogic) AdminGetAgentProductConfigList(req *types.AdminGetAgentProductConfigListReq) (resp *types.AdminGetAgentProductConfigListResp, err error) {
|
||||||
builder := l.svcCtx.AgentProductConfigModel.SelectBuilder().
|
builder := l.svcCtx.AgentProductConfigModel.SelectBuilder()
|
||||||
Where("del_state = ?", globalkey.DelStateNo)
|
|
||||||
|
|
||||||
// 如果提供了产品ID,直接过滤
|
// 如果提供了产品ID,直接过滤
|
||||||
if req.ProductId != nil {
|
if req.ProductId != nil {
|
||||||
@@ -38,7 +36,7 @@ func (l *AdminGetAgentProductConfigListLogic) AdminGetAgentProductConfigList(req
|
|||||||
|
|
||||||
// 如果提供了产品名称,通过关联查询 product 表过滤
|
// 如果提供了产品名称,通过关联查询 product 表过滤
|
||||||
if req.ProductName != nil && *req.ProductName != "" {
|
if req.ProductName != nil && *req.ProductName != "" {
|
||||||
builder = builder.Where("product_id IN (SELECT id FROM product WHERE product_name LIKE ? AND del_state = ?)", "%"+*req.ProductName+"%", globalkey.DelStateNo)
|
builder = builder.Where("product_id IN (SELECT id FROM product WHERE product_name LIKE ?)", "%"+*req.ProductName+"%")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分页查询
|
// 分页查询
|
||||||
|
|||||||
@@ -96,7 +96,19 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
|
|||||||
if l.svcCtx.EasyPayService == nil {
|
if l.svcCtx.EasyPayService == nil {
|
||||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "易支付服务未启用")
|
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "易支付服务未启用")
|
||||||
}
|
}
|
||||||
prepayData, createOrderErr = l.svcCtx.EasyPayService.CreateEasyPayOrder(l.ctx, paymentTypeResp.amount, paymentTypeResp.description, paymentTypeResp.outTradeNo)
|
// 获取用户ID用于次数轮询模式
|
||||||
|
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
||||||
|
if getUidErr != nil {
|
||||||
|
// 如果获取用户ID失败,使用空字符串(会回退到天数轮询)
|
||||||
|
userID = ""
|
||||||
|
}
|
||||||
|
easyPayResult, createOrderErr := l.svcCtx.EasyPayService.CreateEasyPayOrder(l.ctx, paymentTypeResp.amount, paymentTypeResp.description, paymentTypeResp.outTradeNo, userID)
|
||||||
|
if createOrderErr == nil && easyPayResult != nil {
|
||||||
|
prepayData = easyPayResult.PayURL
|
||||||
|
// 将渠道ID存储到context中,后续创建订单时使用
|
||||||
|
ctx = context.WithValue(ctx, "easypay_cid", easyPayResult.CID)
|
||||||
|
l.ctx = ctx
|
||||||
|
}
|
||||||
} else if req.PayMethod == "appleiap" {
|
} else if req.PayMethod == "appleiap" {
|
||||||
prepayData = l.svcCtx.ApplePayService.GetIappayAppID(paymentTypeResp.outTradeNo)
|
prepayData = l.svcCtx.ApplePayService.GetIappayAppID(paymentTypeResp.outTradeNo)
|
||||||
}
|
}
|
||||||
@@ -228,6 +240,12 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
|
|||||||
Amount: amount,
|
Amount: amount,
|
||||||
Status: "pending",
|
Status: "pending",
|
||||||
}
|
}
|
||||||
|
// 如果是易支付,记录使用的渠道ID到备注字段
|
||||||
|
if req.PayMethod == "easypay_alipay" {
|
||||||
|
if cid, ok := l.ctx.Value("easypay_cid").(string); ok && cid != "" {
|
||||||
|
order.Remark = sql.NullString{String: fmt.Sprintf("易支付渠道号: %s", cid), Valid: true}
|
||||||
|
}
|
||||||
|
}
|
||||||
_, insertOrderErr := l.svcCtx.OrderModel.Insert(l.ctx, session, &order)
|
_, insertOrderErr := l.svcCtx.OrderModel.Insert(l.ctx, session, &order)
|
||||||
if insertOrderErr != nil {
|
if insertOrderErr != nil {
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存订单失败: %+v", insertOrderErr)
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存订单失败: %+v", insertOrderErr)
|
||||||
|
|||||||
@@ -19,17 +19,126 @@ import (
|
|||||||
|
|
||||||
// EasyPayService 易支付服务
|
// EasyPayService 易支付服务
|
||||||
type EasyPayService struct {
|
type EasyPayService struct {
|
||||||
config config.EasyPayConfig
|
config config.EasyPayConfig
|
||||||
client *http.Client
|
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 创建易支付服务实例
|
// NewEasyPayService 创建易支付服务实例
|
||||||
func NewEasyPayService(c config.Config) *EasyPayService {
|
func NewEasyPayService(c config.Config, orderModel model.OrderModel) *EasyPayService {
|
||||||
return &EasyPayService{
|
return &EasyPayService{
|
||||||
config: c.EasyPay,
|
config: c.EasyPay,
|
||||||
client: &http.Client{
|
client: &http.Client{
|
||||||
Timeout: 30 * time.Second,
|
Timeout: 30 * time.Second,
|
||||||
},
|
},
|
||||||
|
orderModel: orderModel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +298,7 @@ func (e *EasyPayService) verifySign(params map[string]string, sign string) bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateEasyPayH5Order 创建易支付H5订单(页面跳转方式)
|
// 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)
|
moneyStr := fmt.Sprintf("%.2f", amount)
|
||||||
|
|
||||||
@@ -203,9 +312,9 @@ func (e *EasyPayService) CreateEasyPayH5Order(amount float64, subject string, ou
|
|||||||
"return_url": e.config.ReturnUrl,
|
"return_url": e.config.ReturnUrl,
|
||||||
"sign_type": "MD5",
|
"sign_type": "MD5",
|
||||||
}
|
}
|
||||||
// 如果配置了渠道ID,则添加
|
// 获取并添加渠道ID
|
||||||
if e.config.CID != "" {
|
if cid := e.getSelectedCID(ctx, userID); cid != "" {
|
||||||
params["cid"] = e.config.CID
|
params["cid"] = cid
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成签名
|
// 生成签名
|
||||||
@@ -226,7 +335,7 @@ func (e *EasyPayService) CreateEasyPayH5Order(amount float64, subject string, ou
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateEasyPayAppOrder 创建易支付APP订单(API方式)
|
// 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)
|
moneyStr := fmt.Sprintf("%.2f", amount)
|
||||||
|
|
||||||
@@ -241,9 +350,9 @@ func (e *EasyPayService) CreateEasyPayAppOrder(ctx context.Context, amount float
|
|||||||
"device": "pc",
|
"device": "pc",
|
||||||
"sign_type": "MD5",
|
"sign_type": "MD5",
|
||||||
}
|
}
|
||||||
// 如果配置了渠道ID,则添加
|
// 获取并添加渠道ID
|
||||||
if e.config.CID != "" {
|
if cid := e.getSelectedCID(ctx, userID); cid != "" {
|
||||||
params["cid"] = e.config.CID
|
params["cid"] = cid
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成签名
|
// 生成签名
|
||||||
@@ -302,14 +411,25 @@ func (e *EasyPayService) CreateEasyPayAppOrder(ctx context.Context, amount float
|
|||||||
return "", fmt.Errorf("未获取到支付链接")
|
return "", fmt.Errorf("未获取到支付链接")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateEasyPayOrderResult 易支付订单创建结果
|
||||||
|
type CreateEasyPayOrderResult struct {
|
||||||
|
PayURL string // 支付URL
|
||||||
|
CID string // 使用的渠道ID
|
||||||
|
}
|
||||||
|
|
||||||
// CreateEasyPayOrder 根据平台类型创建易支付订单
|
// 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 判断平台
|
// 根据 ctx 中的 platform 判断平台
|
||||||
platform, platformOk := ctx.Value("platform").(string)
|
platform, platformOk := ctx.Value("platform").(string)
|
||||||
if !platformOk {
|
if !platformOk {
|
||||||
return "", fmt.Errorf("无效的支付平台")
|
return nil, fmt.Errorf("无效的支付平台")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var payURL string
|
||||||
|
var err error
|
||||||
switch platform {
|
switch platform {
|
||||||
case model.PlatformApp:
|
case model.PlatformApp:
|
||||||
// APP平台使用API方式
|
// APP平台使用API方式
|
||||||
@@ -317,13 +437,22 @@ func (e *EasyPayService) CreateEasyPayOrder(ctx context.Context, amount float64,
|
|||||||
if ip, ok := ctx.Value("client_ip").(string); ok {
|
if ip, ok := ctx.Value("client_ip").(string); ok {
|
||||||
clientIP = ip
|
clientIP = ip
|
||||||
}
|
}
|
||||||
return e.CreateEasyPayAppOrder(ctx, amount, subject, outTradeNo, clientIP)
|
payURL, err = e.CreateEasyPayAppOrder(ctx, amount, subject, outTradeNo, clientIP, userID)
|
||||||
case model.PlatformH5:
|
case model.PlatformH5:
|
||||||
// H5平台使用页面跳转方式
|
// H5平台使用页面跳转方式
|
||||||
return e.CreateEasyPayH5Order(amount, subject, outTradeNo)
|
payURL, err = e.CreateEasyPayH5Order(ctx, amount, subject, outTradeNo, userID)
|
||||||
default:
|
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 处理易支付回调通知
|
// HandleEasyPayNotification 处理易支付回调通知
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
|||||||
// 根据配置决定是否初始化易支付服务
|
// 根据配置决定是否初始化易支付服务
|
||||||
var easyPayService *service.EasyPayService
|
var easyPayService *service.EasyPayService
|
||||||
if c.EasyPay.Enabled {
|
if c.EasyPay.Enabled {
|
||||||
easyPayService = service.NewEasyPayService(c)
|
easyPayService = service.NewEasyPayService(c, orderModel)
|
||||||
logx.Info("易支付服务已启用")
|
logx.Info("易支付服务已启用")
|
||||||
} else {
|
} else {
|
||||||
logx.Info("易支付服务已禁用")
|
logx.Info("易支付服务已禁用")
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ type (
|
|||||||
RefundTime sql.NullTime `db:"refund_time"` // 退款时间
|
RefundTime sql.NullTime `db:"refund_time"` // 退款时间
|
||||||
CloseTime sql.NullTime `db:"close_time"` // 订单关闭时间
|
CloseTime sql.NullTime `db:"close_time"` // 订单关闭时间
|
||||||
DeleteTime sql.NullTime `db:"delete_time"` // 删除时间
|
DeleteTime sql.NullTime `db:"delete_time"` // 删除时间
|
||||||
|
Remark sql.NullString `db:"remark"` // 备注信息(如易支付渠道号)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -91,11 +92,11 @@ func (m *defaultOrderModel) Insert(ctx context.Context, session sqlx.Session, da
|
|||||||
jncOrderIdKey := fmt.Sprintf("%s%v", cacheJncOrderIdPrefix, data.Id)
|
jncOrderIdKey := fmt.Sprintf("%s%v", cacheJncOrderIdPrefix, data.Id)
|
||||||
jncOrderOrderNoKey := fmt.Sprintf("%s%v", cacheJncOrderOrderNoPrefix, data.OrderNo)
|
jncOrderOrderNoKey := fmt.Sprintf("%s%v", cacheJncOrderOrderNoPrefix, data.OrderNo)
|
||||||
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, orderRowsExpectAutoSet)
|
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, orderRowsExpectAutoSet)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, data.Id, data.OrderNo, data.UserId, data.ProductId, data.PaymentPlatform, data.PaymentScene, data.PlatformOrderId, data.Amount, data.Status, data.DelState, data.Version, data.PayTime, data.RefundTime, data.CloseTime, data.DeleteTime)
|
return session.ExecCtx(ctx, query, data.Id, data.OrderNo, data.UserId, data.ProductId, data.PaymentPlatform, data.PaymentScene, data.PlatformOrderId, data.Amount, data.Status, data.DelState, data.Version, data.PayTime, data.RefundTime, data.CloseTime, data.DeleteTime, data.Remark)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, data.Id, data.OrderNo, data.UserId, data.ProductId, data.PaymentPlatform, data.PaymentScene, data.PlatformOrderId, data.Amount, data.Status, data.DelState, data.Version, data.PayTime, data.RefundTime, data.CloseTime, data.DeleteTime)
|
return conn.ExecCtx(ctx, query, data.Id, data.OrderNo, data.UserId, data.ProductId, data.PaymentPlatform, data.PaymentScene, data.PlatformOrderId, data.Amount, data.Status, data.DelState, data.Version, data.PayTime, data.RefundTime, data.CloseTime, data.DeleteTime, data.Remark)
|
||||||
}, jncOrderIdKey, jncOrderOrderNoKey)
|
}, jncOrderIdKey, jncOrderOrderNoKey)
|
||||||
}
|
}
|
||||||
func (m *defaultOrderModel) insertUUID(data *Order) {
|
func (m *defaultOrderModel) insertUUID(data *Order) {
|
||||||
@@ -162,9 +163,9 @@ func (m *defaultOrderModel) Update(ctx context.Context, session sqlx.Session, ne
|
|||||||
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, orderRowsWithPlaceHolder)
|
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, orderRowsWithPlaceHolder)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id)
|
return session.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Remark, newData.Id)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id)
|
return conn.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Remark, newData.Id)
|
||||||
}, jncOrderIdKey, jncOrderOrderNoKey)
|
}, jncOrderIdKey, jncOrderOrderNoKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,9 +186,9 @@ func (m *defaultOrderModel) UpdateWithVersion(ctx context.Context, session sqlx.
|
|||||||
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, orderRowsWithPlaceHolder)
|
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, orderRowsWithPlaceHolder)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id, oldVersion)
|
return session.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Remark, newData.Id, oldVersion)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id, oldVersion)
|
return conn.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Remark, newData.Id, oldVersion)
|
||||||
}, jncOrderIdKey, jncOrderOrderNoKey)
|
}, jncOrderIdKey, jncOrderOrderNoKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ $tables = @(
|
|||||||
# "agent_order", # 代理订单
|
# "agent_order", # 代理订单
|
||||||
# "agent_product_config", # 产品配置
|
# "agent_product_config", # 产品配置
|
||||||
# "agent_short_link", # 短链接
|
# "agent_short_link", # 短链接
|
||||||
"agent_wallet", # 钱包
|
# "agent_wallet", # 钱包
|
||||||
"agent_withdraw" # 提现
|
# "agent_withdraw" # 提现
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# 业务功能表
|
# 业务功能表
|
||||||
@@ -44,7 +44,7 @@ $tables = @(
|
|||||||
# "example", # 示例
|
# "example", # 示例
|
||||||
# "feature", # 功能
|
# "feature", # 功能
|
||||||
# "global_notifications", # 全局通知
|
# "global_notifications", # 全局通知
|
||||||
# "order", # 订单
|
"order" # 订单
|
||||||
# "order_refund", # 订单退款
|
# "order_refund", # 订单退款
|
||||||
# "product", # 产品
|
# "product", # 产品
|
||||||
# "product_feature", # 产品功能
|
# "product_feature", # 产品功能
|
||||||
@@ -55,6 +55,7 @@ $tables = @(
|
|||||||
# "user", # 用户
|
# "user", # 用户
|
||||||
# "user_auth", # 用户认证
|
# "user_auth", # 用户认证
|
||||||
# "user_temp" # 临时用户
|
# "user_temp" # 临时用户
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# 为每个表生成模型
|
# 为每个表生成模型
|
||||||
|
|||||||
5
deploy/sql/add_order_remark_field.sql
Normal file
5
deploy/sql/add_order_remark_field.sql
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
-- 为 order 表添加备注字段
|
||||||
|
-- 用于记录易支付使用的渠道号等信息
|
||||||
|
|
||||||
|
ALTER TABLE `order`
|
||||||
|
ADD COLUMN `remark` VARCHAR(255) NULL COMMENT '备注信息(如易支付渠道号)' AFTER `delete_time`;
|
||||||
Reference in New Issue
Block a user