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

@@ -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"

View File

@@ -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"

View File

@@ -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 // 页面跳转地址
} }

View File

@@ -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
} }

View File

@@ -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
} }

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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+"%")
} }
// 分页查询 // 分页查询

View File

@@ -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)

View File

@@ -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 处理易支付回调通知

View File

@@ -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("易支付服务已禁用")

View File

@@ -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

View File

@@ -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" # 临时用户
) )
# 为每个表生成模型 # 为每个表生成模型

View File

@@ -0,0 +1,5 @@
-- 为 order 表添加备注字段
-- 用于记录易支付使用的渠道号等信息
ALTER TABLE `order`
ADD COLUMN `remark` VARCHAR(255) NULL COMMENT '备注信息(如易支付渠道号)' AFTER `delete_time`;