feat(jd-cookie): 引入用户订单号支持并重构订单创建逻辑
- 新增用户订单号字段以区分内部订单号 - 修改订单表结构添加 user_order_id 字段及索引 - 更新 CreateOrder 接口支持用户订单号参数-重构 CreateOrder 和 GetPaymentUrl 方法返回统一结果对象 - 新增模型定义用于封装订单创建与支付结果 - 调整相关逻辑方法签名与调用方式适配新结构- 优化订单创建流程增加内部订单号生成逻辑 - 完善订单查询逻辑确保正确关联用户订单号- 更新控制器层对接新版服务接口- 升级 Cookie 状态及订单状态管理枚举类型使用
This commit is contained in:
@@ -29,7 +29,7 @@ type JdCookieOrderApi struct {
|
||||
// CreateOrderReq Create Order Request
|
||||
type CreateOrderReq struct {
|
||||
g.Meta `path:"/jd-cookie/order/create" method:"post" summary:"Create Order" tags:"JD Order Management"`
|
||||
OrderId string `json:"orderId" v:"required#订单号不能为空" dc:"订单号"`
|
||||
UserOrderId string `json:"userOrderId" v:"required#用户订单号不能为空" dc:"用户订单号"`
|
||||
Amount float64 `json:"amount" v:"required|min:0.01#订单金额不能为空|订单金额必须大于0" dc:"订单金额"`
|
||||
Category consts.RedeemOrderCardCategory `json:"category" v:"required#商品品类不能为空" dc:"商品品类"`
|
||||
}
|
||||
@@ -38,6 +38,7 @@ type CreateOrderRes struct {
|
||||
g.Meta `mime:"application/json"`
|
||||
WxPayUrl string `json:"wxPayUrl" dc:"微信支付链接"`
|
||||
JdOrderId string `json:"jdOrderId" dc:"京东订单号"`
|
||||
OrderId string `json:"orderId" dc:"内部订单号"`
|
||||
}
|
||||
|
||||
// GetPaymentUrlReq Get Payment URL Request
|
||||
@@ -49,6 +50,8 @@ type GetPaymentUrlReq struct {
|
||||
type GetPaymentUrlRes struct {
|
||||
g.Meta `mime:"application/json"`
|
||||
WxPayUrl string `json:"wxPayUrl" dc:"微信支付链接"`
|
||||
JdOrderId string `json:"jdOrderId" dc:"京东订单号"`
|
||||
OrderId string `json:"orderId" dc:"内部订单号"`
|
||||
}
|
||||
|
||||
// GetOrderStatusReq Query Order Status Request
|
||||
@@ -96,14 +99,24 @@ type OrderInfo struct {
|
||||
}
|
||||
|
||||
type JdOrderInfo struct {
|
||||
Id int64 `json:"id" dc:"主键ID"`
|
||||
JdOrderId string `json:"jdOrderId" dc:"京东订单号"`
|
||||
OrderId string `json:"orderId" dc:"关联的内部订单号"`
|
||||
PayId string `json:"payId" dc:"支付ID"`
|
||||
Amount float64 `json:"amount" dc:"订单金额"`
|
||||
Category string `json:"category" dc:"商品品类"`
|
||||
CookieId string `json:"cookieId" dc:"使用的Cookie ID"`
|
||||
Status consts.JdOrderStatus `json:"status" dc:"状态:1待支付 2已支付 3已过期 4已取消"`
|
||||
PaidAt string `json:"paidAt" dc:"支付时间"`
|
||||
CreatedAt string `json:"createdAt" dc:"创建时间"`
|
||||
UpdatedAt string `json:"updatedAt" dc:"更新时间"`
|
||||
WxPayUrl string `json:"wxPayUrl" dc:"微信支付链接"`
|
||||
WxPayExpireAt *string `json:"wxPayExpireAt" dc:"微信支付链接过期时间"`
|
||||
OrderExpireAt *string `json:"orderExpireAt" dc:"订单过期时间(默认24小时)"`
|
||||
CurrentOrderId int64 `json:"currentOrderId" dc:"当前关联的订单ID"`
|
||||
PaidAt *string `json:"paidAt" dc:"支付完成时间"`
|
||||
CardNo string `json:"cardNo" dc:"卡号"`
|
||||
CardPassword string `json:"cardPassword" dc:"卡密"`
|
||||
CardExtractedAt *string `json:"cardExtractedAt" dc:"卡密提取时间"`
|
||||
CreatedAt *string `json:"createdAt" dc:"创建时间"`
|
||||
UpdatedAt *string `json:"updatedAt" dc:"更新时间"`
|
||||
DeletedAt *string `json:"deletedAt" dc:"删除时间"`
|
||||
}
|
||||
|
||||
// ListOrderReq Order List Query Request
|
||||
|
||||
@@ -11,14 +11,15 @@ import (
|
||||
|
||||
// CreateOrder 创建订单
|
||||
func (c *ControllerV1) CreateOrder(ctx context.Context, req *v1.CreateOrderReq) (res *v1.CreateOrderRes, err error) {
|
||||
wxPayUrl, jdOrderId, err := service.JdCookie().CreateOrder(ctx, req.OrderId, req.Amount, req.Category)
|
||||
result, err := service.JdCookie().CreateOrder(ctx, req.UserOrderId, req.Amount, req.Category)
|
||||
if err != nil {
|
||||
return nil, gerror.WrapCode(gcode.CodeInternalError, err, "创建订单失败")
|
||||
}
|
||||
|
||||
res = &v1.CreateOrderRes{
|
||||
WxPayUrl: wxPayUrl,
|
||||
JdOrderId: jdOrderId,
|
||||
WxPayUrl: result.WxPayUrl,
|
||||
JdOrderId: result.JdOrderId,
|
||||
OrderId: result.OrderId,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -18,13 +18,15 @@ func (c *ControllerV1) GetPaymentUrl(ctx context.Context, req *v1.GetPaymentUrlR
|
||||
return
|
||||
}
|
||||
|
||||
wxPayUrl, _, err := service.JdCookie().GetPaymentUrl(ctx, req.OrderId)
|
||||
result, err := service.JdCookie().GetPaymentUrl(ctx, req.OrderId)
|
||||
if err != nil {
|
||||
return nil, gerror.WrapCode(gcode.CodeInternalError, err, "获取支付链接失败")
|
||||
}
|
||||
|
||||
res = &v1.GetPaymentUrlRes{
|
||||
WxPayUrl: wxPayUrl,
|
||||
WxPayUrl: result.WxPayUrl,
|
||||
JdOrderId: result.JdOrderId,
|
||||
OrderId: result.OrderId,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ type V1JdCookieOrderDao struct {
|
||||
type V1JdCookieOrderColumns struct {
|
||||
Id string // 主键ID
|
||||
OrderId string // 订单号
|
||||
UserOrderId string // 用户订单号
|
||||
Amount string // 订单金额
|
||||
Category string // 商品品类
|
||||
JdOrderId string // 关联的京东订单号
|
||||
@@ -38,6 +39,7 @@ type V1JdCookieOrderColumns struct {
|
||||
var v1JdCookieOrderColumns = V1JdCookieOrderColumns{
|
||||
Id: "id",
|
||||
OrderId: "order_id",
|
||||
UserOrderId: "user_order_id",
|
||||
Amount: "amount",
|
||||
Category: "category",
|
||||
JdOrderId: "jd_order_id",
|
||||
|
||||
@@ -3,116 +3,142 @@ package jd_cookie
|
||||
import (
|
||||
"context"
|
||||
"kami/internal/consts"
|
||||
"kami/internal/model"
|
||||
"kami/utility/utils"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// CreateOrder 创建订单
|
||||
func (s *sJdCookie) CreateOrder(ctx context.Context, orderId string, amount float64, category consts.RedeemOrderCardCategory) (wxPayUrl, jdOrderId string, err error) {
|
||||
func (s *sJdCookie) CreateOrder(ctx context.Context, userOrderId string, amount float64, category consts.RedeemOrderCardCategory) (result *model.CreateOrderResult, err error) {
|
||||
_ = s.ReleaseExpiredJdOrders(ctx)
|
||||
|
||||
if orderId == "" {
|
||||
return "", "", gerror.New("订单号不能为空")
|
||||
if userOrderId == "" {
|
||||
return nil, gerror.New("用户订单号不能为空")
|
||||
}
|
||||
if amount <= 0 {
|
||||
return "", "", gerror.New("订单金额必须大于0")
|
||||
return nil, gerror.New("订单金额必须大于0")
|
||||
}
|
||||
|
||||
// 检查订单是否已存在
|
||||
existingOrder, err := s.getOrderByOrderId(ctx, orderId)
|
||||
// 检查用户订单是否已存在
|
||||
existingOrder, err := s.getOrderByUserOrderId(ctx, userOrderId)
|
||||
if err != nil {
|
||||
return "", "", gerror.Wrap(err, "检查订单是否存在失败")
|
||||
return nil, gerror.Wrap(err, "检查用户订单是否存在失败")
|
||||
}
|
||||
//
|
||||
if existingOrder != nil {
|
||||
// 订单已存在,尝试获取支付链接
|
||||
return s.GetPaymentUrl(ctx, orderId)
|
||||
paymentResult, err := s.GetPaymentUrl(ctx, existingOrder.OrderId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//
|
||||
//// 优先尝试复用现有的京东订单
|
||||
//reusableJdOrder, err := s.findReusableJdOrder(ctx, amount, category)
|
||||
//if err != nil {
|
||||
// glog.Warning(ctx, "查找可复用京东订单失败", err)
|
||||
//}
|
||||
//
|
||||
var cookieId string
|
||||
//var isReused bool = false
|
||||
//
|
||||
//if reusableJdOrder != nil {
|
||||
// // 尝试使用可复用的京东订单
|
||||
// jdOrderId = reusableJdOrder.JdOrderId
|
||||
// cookieId = reusableJdOrder.CookieId
|
||||
// wxPayUrl = reusableJdOrder.WxPayUrl
|
||||
//
|
||||
// // 检查支付链接是否过期
|
||||
// if reusableJdOrder.WxPayExpireAt != nil && gtime.Now().After(reusableJdOrder.WxPayExpireAt) {
|
||||
// // 支付链接已过期,尝试刷新
|
||||
// newWxPayUrl, refreshErr := s.refreshPaymentUrl(ctx, jdOrderId, reusableJdOrder.PayId, cookieId, orderId)
|
||||
// if refreshErr != nil {
|
||||
// glog.Warning(ctx, "刷新支付链接失败,将创建新订单", g.Map{
|
||||
// "jdOrderId": jdOrderId,
|
||||
// "error": refreshErr,
|
||||
// })
|
||||
// // 刷新失败,标记为不可复用
|
||||
// _ = s.UpdateJdOrderStatus(ctx, jdOrderId, int(consts.JdOrderStatusExpired), "刷新支付链接失败")
|
||||
// _ = s.RecordJdOrderHistory(ctx, jdOrderId, string(consts.JdOrderChangeTypeInvalid), "", reusableJdOrder.WxPayUrl)
|
||||
//
|
||||
// // 记录Cookie刷新失败历史
|
||||
// _ = s.RecordCookieHistory(ctx, cookieId, string(consts.CookieChangeTypeRefreshFail), 0, 0, orderId, 0)
|
||||
//
|
||||
// // 清空,准备创建新订单
|
||||
// jdOrderId = ""
|
||||
// cookieId = ""
|
||||
// wxPayUrl = ""
|
||||
// } else {
|
||||
// wxPayUrl = newWxPayUrl
|
||||
// // 更新京东订单的支付链接和过期时间
|
||||
// _ = s.updateJdOrderPaymentUrl(ctx, jdOrderId, wxPayUrl)
|
||||
// isReused = true
|
||||
// }
|
||||
// } else {
|
||||
// isReused = true
|
||||
// }
|
||||
//
|
||||
// if isReused {
|
||||
// glog.Info(ctx, "复用现有京东订单", g.Map{
|
||||
// "orderId": orderId,
|
||||
// "jdOrderId": jdOrderId,
|
||||
// "cookieId": cookieId,
|
||||
// })
|
||||
// }
|
||||
//}
|
||||
//
|
||||
// 转换为CreateOrderResult
|
||||
return &model.CreateOrderResult{
|
||||
WxPayUrl: paymentResult.WxPayUrl,
|
||||
JdOrderId: paymentResult.JdOrderId,
|
||||
OrderId: paymentResult.OrderId,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 优先尝试复用现有的京东订单
|
||||
reusableJdOrder, err := s.findReusableJdOrder(ctx, amount, category)
|
||||
if err != nil {
|
||||
glog.Warning(ctx, "查找可复用京东订单失败", err)
|
||||
}
|
||||
|
||||
// 生成内部订单ID
|
||||
internalOrderId := "JD_" + utils.GenerateRandomUUID()
|
||||
|
||||
var cookieId, jdOrderId, wxPayUrl string
|
||||
var isReused = false
|
||||
|
||||
if reusableJdOrder != nil {
|
||||
// 尝试使用可复用的京东订单
|
||||
jdOrderId = reusableJdOrder.JdOrderId
|
||||
cookieId = reusableJdOrder.CookieId
|
||||
wxPayUrl = reusableJdOrder.WxPayUrl
|
||||
|
||||
// 检查支付链接是否过期
|
||||
if reusableJdOrder.WxPayExpireAt != nil && gtime.Now().After(reusableJdOrder.WxPayExpireAt) {
|
||||
// 支付链接已过期,尝试刷新
|
||||
newWxPayUrl, refreshErr := s.refreshPaymentUrl(ctx, jdOrderId, reusableJdOrder.PayId, cookieId, internalOrderId)
|
||||
if refreshErr != nil {
|
||||
glog.Warning(ctx, "刷新支付链接失败,将创建新订单", g.Map{
|
||||
"jdOrderId": jdOrderId,
|
||||
"error": refreshErr,
|
||||
})
|
||||
// 刷新失败,标记为不可复用
|
||||
_ = s.UpdateJdOrderStatus(ctx, jdOrderId, consts.JdOrderStatusExpired, "刷新支付链接失败")
|
||||
_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypeInvalid, "", reusableJdOrder.WxPayUrl)
|
||||
|
||||
// 记录Cookie刷新失败历史
|
||||
_ = s.RecordCookieHistory(ctx, cookieId, consts.CookieChangeTypeRefreshFail, 0, 0, internalOrderId, 0)
|
||||
|
||||
// 清空,准备创建新订单
|
||||
jdOrderId = ""
|
||||
cookieId = ""
|
||||
wxPayUrl = ""
|
||||
} else {
|
||||
wxPayUrl = newWxPayUrl
|
||||
// 更新京东订单的支付链接和过期时间
|
||||
_ = s.updateJdOrderPaymentUrl(ctx, jdOrderId, wxPayUrl)
|
||||
isReused = true
|
||||
}
|
||||
} else {
|
||||
isReused = true
|
||||
}
|
||||
|
||||
if isReused {
|
||||
glog.Info(ctx, "复用现有京东订单", g.Map{
|
||||
"orderId": internalOrderId,
|
||||
"jdOrderId": jdOrderId,
|
||||
"cookieId": cookieId,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有成功复用,创建新的京东订单
|
||||
if jdOrderId == "" {
|
||||
jdOrderId, cookieId, wxPayUrl, err = s.createNewJdOrderWithRetry(ctx, orderId, amount, category)
|
||||
retryRes, err := s.createNewJdOrderWithRetry(ctx, &model.CreateNewJdOrderWithRetryReq{
|
||||
OrderId: internalOrderId,
|
||||
Amount: amount,
|
||||
Category: category,
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return nil, err
|
||||
}
|
||||
jdOrderId = retryRes.JdOrderId
|
||||
cookieId = retryRes.CookieId
|
||||
wxPayUrl = retryRes.WxPayUrl
|
||||
}
|
||||
|
||||
// 创建订单记录
|
||||
err = s.createOrderRecord(ctx, orderId, amount, category, jdOrderId, wxPayUrl)
|
||||
err = s.createOrderRecord(ctx, internalOrderId, userOrderId, amount, category, jdOrderId, wxPayUrl)
|
||||
if err != nil {
|
||||
return "", "", gerror.Wrap(err, "创建订单记录失败")
|
||||
return nil, gerror.Wrap(err, "创建订单记录失败")
|
||||
}
|
||||
|
||||
// 更新京东订单的当前关联订单ID
|
||||
_ = s.updateJdOrderCurrentOrderId(ctx, jdOrderId, orderId)
|
||||
_ = s.updateJdOrderCurrentOrderId(ctx, jdOrderId, internalOrderId)
|
||||
|
||||
// 记录Cookie使用历史
|
||||
_ = s.RecordCookieHistory(ctx, cookieId, consts.CookieChangeTypeUse, 0, 0, orderId, 0)
|
||||
_ = s.RecordCookieHistory(ctx, cookieId, consts.CookieChangeTypeUse, 0, 0, internalOrderId, 0)
|
||||
|
||||
// 记录订单创建历史
|
||||
_ = s.RecordOrderHistory(ctx, orderId, consts.OrderChangeTypeCreate, jdOrderId)
|
||||
_ = s.RecordOrderHistory(ctx, internalOrderId, consts.OrderChangeTypeCreate, jdOrderId)
|
||||
|
||||
return wxPayUrl, jdOrderId, nil
|
||||
return &model.CreateOrderResult{
|
||||
WxPayUrl: wxPayUrl,
|
||||
JdOrderId: jdOrderId,
|
||||
OrderId: internalOrderId,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// createNewJdOrderWithRetry 创建新的京东订单(带重试机制)
|
||||
func (s *sJdCookie) createNewJdOrderWithRetry(ctx context.Context, orderId string, amount float64, category consts.RedeemOrderCardCategory) (jdOrderId, cookieId, wxPayUrl string, err error) {
|
||||
func (s *sJdCookie) createNewJdOrderWithRetry(ctx context.Context, req *model.CreateNewJdOrderWithRetryReq) (res *model.CreateNewJdOrderWithRetryRes, err error) {
|
||||
var lastErr error
|
||||
var triedCookies []string // 记录已尝试的Cookie
|
||||
|
||||
@@ -122,7 +148,7 @@ func (s *sJdCookie) createNewJdOrderWithRetry(ctx context.Context, orderId strin
|
||||
availableCookieId, cookieErr := s.GetAvailableCookie(ctx)
|
||||
if cookieErr != nil {
|
||||
glog.Warning(ctx, "获取可用Cookie失败", g.Map{
|
||||
"orderId": orderId,
|
||||
"orderId": req.OrderId,
|
||||
"triedCookies": len(triedCookies),
|
||||
"error": cookieErr,
|
||||
})
|
||||
@@ -143,44 +169,48 @@ func (s *sJdCookie) createNewJdOrderWithRetry(ctx context.Context, orderId strin
|
||||
|
||||
// 调用京东下单接口
|
||||
var payId string
|
||||
jdOrderId, payId, wxPayUrl, lastErr = s.callJdCreateOrder(ctx, availableCookieId, amount, category)
|
||||
jdOrderId, payId, wxPayUrl, lastErr := s.callJdCreateOrder(ctx, availableCookieId, req.Amount, req.Category)
|
||||
if lastErr != nil {
|
||||
glog.Warning(ctx, "京东下单失败,尝试切换Cookie重试", g.Map{
|
||||
"orderId": orderId,
|
||||
"orderId": req.OrderId,
|
||||
"cookieId": availableCookieId,
|
||||
"triedCookies": len(triedCookies),
|
||||
"error": lastErr,
|
||||
})
|
||||
|
||||
// Cookie失败,更新状态
|
||||
s.handleCookieFailure(ctx, availableCookieId, orderId)
|
||||
s.handleCookieFailure(ctx, availableCookieId, req.OrderId)
|
||||
|
||||
// 继续下一次重试
|
||||
continue
|
||||
}
|
||||
|
||||
// 下单成功,创建京东订单记录
|
||||
err = s.createJdOrderRecord(ctx, jdOrderId, payId, availableCookieId, category, amount, wxPayUrl)
|
||||
err = s.createJdOrderRecord(ctx, jdOrderId, payId, availableCookieId, req.Category, req.Amount, wxPayUrl)
|
||||
if err != nil {
|
||||
glog.Error(ctx, "创建京东订单记录失败", g.Map{
|
||||
"jdOrderId": jdOrderId,
|
||||
"error": err,
|
||||
})
|
||||
return "", "", "", gerror.Wrap(err, "创建京东订单记录失败")
|
||||
return nil, gerror.Wrap(err, "创建京东订单记录失败")
|
||||
}
|
||||
|
||||
// 记录京东订单创建历史
|
||||
_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypeCreate, orderId, wxPayUrl)
|
||||
_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypeCreate, req.OrderId, wxPayUrl)
|
||||
|
||||
glog.Info(ctx, "创建京东订单成功", g.Map{
|
||||
"orderId": orderId,
|
||||
"orderId": req.OrderId,
|
||||
"jdOrderId": jdOrderId,
|
||||
"cookieId": availableCookieId,
|
||||
"triedCookies": len(triedCookies),
|
||||
})
|
||||
|
||||
// 返回成功结果
|
||||
return jdOrderId, availableCookieId, wxPayUrl, nil
|
||||
return &model.CreateNewJdOrderWithRetryRes{
|
||||
JdOrderId: jdOrderId,
|
||||
CookieId: availableCookieId,
|
||||
WxPayUrl: wxPayUrl,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 所有重试都失败了
|
||||
@@ -189,12 +219,12 @@ func (s *sJdCookie) createNewJdOrderWithRetry(ctx context.Context, orderId strin
|
||||
}
|
||||
|
||||
glog.Error(ctx, "创建京东订单失败,所有Cookie均不可用", g.Map{
|
||||
"orderId": orderId,
|
||||
"orderId": req.OrderId,
|
||||
"triedCookies": triedCookies,
|
||||
"error": lastErr,
|
||||
})
|
||||
|
||||
return "", "", "", gerror.Wrapf(lastErr, "创建京东订单失败,已尝试%d个Cookie", len(triedCookies))
|
||||
return nil, gerror.Wrapf(lastErr, "创建京东订单失败,已尝试%d个Cookie", len(triedCookies))
|
||||
}
|
||||
|
||||
// hasCookieBeenTried 检查Cookie是否已经尝试过
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
v1 "kami/api/jd_cookie/v1"
|
||||
"kami/internal/consts"
|
||||
"kami/internal/dao"
|
||||
"kami/internal/model"
|
||||
"kami/internal/model/entity"
|
||||
"kami/utility/config"
|
||||
|
||||
@@ -14,31 +15,31 @@ import (
|
||||
)
|
||||
|
||||
// GetPaymentUrl 获取支付链接
|
||||
func (s *sJdCookie) GetPaymentUrl(ctx context.Context, orderId string) (wxPayUrl, jdOrderId string, err error) {
|
||||
func (s *sJdCookie) GetPaymentUrl(ctx context.Context, orderId string) (result *model.PaymentResult, err error) {
|
||||
if orderId == "" {
|
||||
return "", "", gerror.New("订单号不能为空")
|
||||
return nil, gerror.New("订单号不能为空")
|
||||
}
|
||||
|
||||
// 获取订单信息
|
||||
order, err := s.getOrderByOrderId(ctx, orderId)
|
||||
if err != nil {
|
||||
return "", "", gerror.Wrap(err, "查询订单失败")
|
||||
return nil, gerror.Wrap(err, "查询订单失败")
|
||||
}
|
||||
if order == nil {
|
||||
return "", "", gerror.New(consts.ErrCodeOrderNotFound)
|
||||
return nil, gerror.New(consts.ErrCodeOrderNotFound)
|
||||
}
|
||||
|
||||
// 获取关联的京东订单
|
||||
jdOrder, err := s.getJdOrderByJdOrderId(ctx, order.JdOrderId)
|
||||
if err != nil {
|
||||
return "", "", gerror.Wrap(err, "查询京东订单失败")
|
||||
return nil, gerror.Wrap(err, "查询京东订单失败")
|
||||
}
|
||||
if jdOrder == nil {
|
||||
return "", "", gerror.New(consts.ErrCodeJdOrderNotFound)
|
||||
return nil, gerror.New(consts.ErrCodeJdOrderNotFound)
|
||||
}
|
||||
|
||||
jdOrderId = jdOrder.JdOrderId
|
||||
wxPayUrl = jdOrder.WxPayUrl
|
||||
jdOrderId := jdOrder.JdOrderId
|
||||
wxPayUrl := jdOrder.WxPayUrl
|
||||
|
||||
// 检查支付链接是否有效
|
||||
if jdOrder.WxPayExpireAt != nil && gtime.Now().After(jdOrder.WxPayExpireAt) {
|
||||
@@ -46,7 +47,7 @@ func (s *sJdCookie) GetPaymentUrl(ctx context.Context, orderId string) (wxPayUrl
|
||||
newWxPayUrl, refreshErr := s.refreshPaymentUrl(ctx, jdOrder.JdOrderId, jdOrder.PayId, jdOrder.CookieId, orderId)
|
||||
if refreshErr != nil {
|
||||
// 刷新失败,标记旧订单为失效
|
||||
_ = s.UpdateJdOrderStatus(ctx, jdOrder.JdOrderId, int(consts.JdOrderStatusExpired), "刷新支付链接失败")
|
||||
_ = s.UpdateJdOrderStatus(ctx, jdOrder.JdOrderId, consts.JdOrderStatusExpired, "刷新支付链接失败")
|
||||
_ = s.RecordJdOrderHistory(ctx, jdOrder.JdOrderId, consts.JdOrderChangeTypeInvalid, orderId, jdOrder.WxPayUrl)
|
||||
_ = s.RecordCookieHistory(ctx, jdOrder.CookieId, consts.CookieChangeTypeRefreshFail, 0, 0, orderId, 0)
|
||||
|
||||
@@ -54,26 +55,30 @@ func (s *sJdCookie) GetPaymentUrl(ctx context.Context, orderId string) (wxPayUrl
|
||||
_ = s.updateJdOrderCurrentOrderId(ctx, jdOrder.JdOrderId, "")
|
||||
|
||||
// 创建新的京东订单(带重试机制)
|
||||
newJdOrderId, newCookieId, newWxPayUrl, createErr := s.createNewJdOrderWithRetry(ctx, orderId, gconv.Float64(order.Amount), consts.RedeemOrderCardCategory(order.Category))
|
||||
retryRes, createErr := s.createNewJdOrderWithRetry(ctx, &model.CreateNewJdOrderWithRetryReq{
|
||||
OrderId: orderId,
|
||||
Amount: gconv.Float64(order.Amount),
|
||||
Category: consts.RedeemOrderCardCategory(order.Category),
|
||||
})
|
||||
if createErr != nil {
|
||||
return "", "", gerror.Wrap(createErr, "刷新失败且创建新订单失败")
|
||||
return nil, gerror.Wrap(createErr, "刷新失败且创建新订单失败")
|
||||
}
|
||||
|
||||
// 更新订单关联的京东订单ID
|
||||
_ = s.updateOrderJdOrderId(ctx, orderId, newJdOrderId, newWxPayUrl)
|
||||
_ = s.updateOrderJdOrderId(ctx, orderId, retryRes.JdOrderId, retryRes.WxPayUrl)
|
||||
|
||||
// 更新京东订单的当前关联订单ID
|
||||
_ = s.updateJdOrderCurrentOrderId(ctx, newJdOrderId, orderId)
|
||||
_ = s.updateJdOrderCurrentOrderId(ctx, retryRes.JdOrderId, orderId)
|
||||
|
||||
// 记录Cookie使用历史
|
||||
_ = s.RecordCookieHistory(ctx, newCookieId, consts.CookieChangeTypeUse, 0, 0, orderId, 0)
|
||||
_ = s.RecordCookieHistory(ctx, retryRes.CookieId, consts.CookieChangeTypeUse, 0, 0, orderId, 0)
|
||||
|
||||
// 记录订单重新绑定历史
|
||||
_ = s.RecordOrderHistory(ctx, orderId, consts.OrderChangeTypeRebind, newJdOrderId)
|
||||
_ = s.RecordOrderHistory(ctx, orderId, consts.OrderChangeTypeRebind, retryRes.JdOrderId)
|
||||
|
||||
// 返回新的支付信息
|
||||
jdOrderId = newJdOrderId
|
||||
wxPayUrl = newWxPayUrl
|
||||
jdOrderId = retryRes.JdOrderId
|
||||
wxPayUrl = retryRes.WxPayUrl
|
||||
} else {
|
||||
// 刷新成功,更新支付链接
|
||||
wxPayUrl = newWxPayUrl
|
||||
@@ -84,7 +89,11 @@ func (s *sJdCookie) GetPaymentUrl(ctx context.Context, orderId string) (wxPayUrl
|
||||
// 更新订单最后请求时间
|
||||
_ = s.updateOrderLastRequest(ctx, orderId)
|
||||
|
||||
return wxPayUrl, jdOrderId, nil
|
||||
return &model.PaymentResult{
|
||||
WxPayUrl: wxPayUrl,
|
||||
JdOrderId: jdOrderId,
|
||||
OrderId: order.OrderId,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetOrder 获取单个订单
|
||||
|
||||
@@ -29,6 +29,14 @@ func (s *sJdCookie) getOrderByOrderId(ctx context.Context, orderId string) (orde
|
||||
return
|
||||
}
|
||||
|
||||
// getOrderByUserOrderId 根据用户订单号查询订单
|
||||
func (s *sJdCookie) getOrderByUserOrderId(ctx context.Context, userOrderId string) (order *entity.V1JdCookieOrder, err error) {
|
||||
m := dao.V1JdCookieOrder.Ctx(ctx).DB(config.GetDatabaseV1())
|
||||
err = m.Where(dao.V1JdCookieOrder.Columns().UserOrderId, userOrderId).Scan(&order)
|
||||
err = utils.HandleNoRowsError(err)
|
||||
return
|
||||
}
|
||||
|
||||
// getJdOrderByJdOrderId 根据京东订单号查询京东订单
|
||||
func (s *sJdCookie) getJdOrderByJdOrderId(ctx context.Context, jdOrderId string) (jdOrder *entity.V1JdCookieJdOrder, err error) {
|
||||
m := dao.V1JdCookieJdOrder.Ctx(ctx).DB(config.GetDatabaseV1())
|
||||
@@ -65,10 +73,11 @@ func (s *sJdCookie) createJdOrderRecord(ctx context.Context, jdOrderId, payId, c
|
||||
}
|
||||
|
||||
// createOrderRecord 创建订单记录
|
||||
func (s *sJdCookie) createOrderRecord(ctx context.Context, orderId string, amount float64, category consts.RedeemOrderCardCategory, jdOrderId, wxPayUrl string) error {
|
||||
func (s *sJdCookie) createOrderRecord(ctx context.Context, internalOrderId, userOrderId string, amount float64, category consts.RedeemOrderCardCategory, jdOrderId, wxPayUrl string) error {
|
||||
m := dao.V1JdCookieOrder.Ctx(ctx).DB(config.GetDatabaseV1())
|
||||
_, err := m.Insert(&do.V1JdCookieOrder{
|
||||
OrderId: orderId,
|
||||
OrderId: internalOrderId,
|
||||
UserOrderId: userOrderId,
|
||||
Amount: amount,
|
||||
Category: category,
|
||||
JdOrderId: jdOrderId,
|
||||
|
||||
@@ -101,7 +101,7 @@ func (s *sJdCookie) unlockExpiredCookies(ctx context.Context) {
|
||||
// ====================================================================================
|
||||
|
||||
// UpdateCookieStatus 更新Cookie状态
|
||||
func (s *sJdCookie) UpdateCookieStatus(ctx context.Context, cookieId string, status int, failureCount int) (err error) {
|
||||
func (s *sJdCookie) UpdateCookieStatus(ctx context.Context, cookieId string, status consts.JdCookieStatus, failureCount int) (err error) {
|
||||
if cookieId == "" {
|
||||
return gerror.New("Cookie ID不能为空")
|
||||
}
|
||||
@@ -119,17 +119,17 @@ func (s *sJdCookie) UpdateCookieStatus(ctx context.Context, cookieId string, sta
|
||||
}
|
||||
|
||||
updateData := &do.V1JdCookieAccount{
|
||||
Status: status,
|
||||
Status: int(status),
|
||||
FailureCount: failureCount,
|
||||
}
|
||||
|
||||
// 如果是暂停状态,设置暂停时间
|
||||
if status == int(consts.JdCookieStatusSuspend) {
|
||||
if status == consts.JdCookieStatusSuspend {
|
||||
updateData.SuspendUntil = gtime.Now().Add(time.Minute * consts.JdCookieSuspendDuration)
|
||||
}
|
||||
|
||||
// 如果是恢复正常状态,清除暂停时间
|
||||
if status == int(consts.JdCookieStatusNormal) {
|
||||
if status == consts.JdCookieStatusNormal {
|
||||
updateData.SuspendUntil = nil
|
||||
}
|
||||
|
||||
@@ -139,20 +139,20 @@ func (s *sJdCookie) UpdateCookieStatus(ctx context.Context, cookieId string, sta
|
||||
}
|
||||
|
||||
// 记录状态变更历史
|
||||
if oldCookie.Status != status || oldCookie.FailureCount != failureCount {
|
||||
if oldCookie.Status != int(status) || oldCookie.FailureCount != failureCount {
|
||||
var changeType consts.CookieChangeType
|
||||
switch status {
|
||||
case int(consts.JdCookieStatusNormal):
|
||||
case consts.JdCookieStatusNormal:
|
||||
changeType = consts.CookieChangeTypeResume
|
||||
case int(consts.JdCookieStatusSuspend):
|
||||
case consts.JdCookieStatusSuspend:
|
||||
changeType = consts.CookieChangeTypeSuspend
|
||||
case int(consts.JdCookieStatusExpired):
|
||||
case consts.JdCookieStatusExpired:
|
||||
changeType = consts.CookieChangeTypeFail
|
||||
default:
|
||||
changeType = consts.CookieChangeTypeUpdate
|
||||
}
|
||||
|
||||
_ = s.RecordCookieHistory(ctx, cookieId, changeType, oldCookie.Status, status, "", failureCount)
|
||||
_ = s.RecordCookieHistory(ctx, cookieId, changeType, oldCookie.Status, int(status), "", failureCount)
|
||||
}
|
||||
|
||||
return
|
||||
@@ -190,7 +190,7 @@ func (s *sJdCookie) CreateJdOrder(ctx context.Context, jdOrderId, payId, cookieI
|
||||
}
|
||||
|
||||
// UpdateJdOrderStatus 更新京东订单状态
|
||||
func (s *sJdCookie) UpdateJdOrderStatus(ctx context.Context, jdOrderId string, status int, wxPayUrl string) (err error) {
|
||||
func (s *sJdCookie) UpdateJdOrderStatus(ctx context.Context, jdOrderId string, status consts.JdOrderStatus, wxPayUrl string) (err error) {
|
||||
if jdOrderId == "" {
|
||||
return gerror.New("京东订单号不能为空")
|
||||
}
|
||||
@@ -208,7 +208,7 @@ func (s *sJdCookie) UpdateJdOrderStatus(ctx context.Context, jdOrderId string, s
|
||||
}
|
||||
|
||||
updateData := &do.V1JdCookieJdOrder{
|
||||
Status: status,
|
||||
Status: int(status),
|
||||
}
|
||||
|
||||
if wxPayUrl != "" {
|
||||
@@ -222,14 +222,14 @@ func (s *sJdCookie) UpdateJdOrderStatus(ctx context.Context, jdOrderId string, s
|
||||
}
|
||||
|
||||
// 记录状态变更历史
|
||||
if oldOrder.Status != status {
|
||||
if oldOrder.Status != int(status) {
|
||||
var changeType consts.JdOrderChangeType
|
||||
switch status {
|
||||
case int(consts.JdOrderStatusPaid):
|
||||
case consts.JdOrderStatusPaid:
|
||||
changeType = consts.JdOrderChangeTypePay
|
||||
case int(consts.JdOrderStatusExpired):
|
||||
case consts.JdOrderStatusExpired:
|
||||
changeType = consts.JdOrderChangeTypeExpire
|
||||
case int(consts.JdOrderStatusCanceled):
|
||||
case consts.JdOrderStatusCanceled:
|
||||
changeType = consts.JdOrderChangeTypeInvalid
|
||||
default:
|
||||
changeType = consts.JdOrderChangeTypeReplace
|
||||
|
||||
@@ -14,6 +14,7 @@ type V1JdCookieOrder struct {
|
||||
g.Meta `orm:"table:jd_cookie_order, do:true"`
|
||||
Id any // 主键ID
|
||||
OrderId any // 订单号
|
||||
UserOrderId any // 用户订单号
|
||||
Amount any // 订单金额
|
||||
Category any // 商品品类
|
||||
JdOrderId any // 关联的京东订单号
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
type V1JdCookieOrder struct {
|
||||
Id int64 `json:"id" orm:"id" description:"主键ID"`
|
||||
OrderId string `json:"orderId" orm:"order_id" description:"订单号"`
|
||||
UserOrderId string `json:"userOrderId" orm:"user_order_id" description:"用户订单号"`
|
||||
Amount decimal.Decimal `json:"amount" orm:"amount" description:"订单金额"`
|
||||
Category string `json:"category" orm:"category" description:"商品品类"`
|
||||
JdOrderId string `json:"jdOrderId" orm:"jd_order_id" description:"关联的京东订单号"`
|
||||
|
||||
35
internal/model/jd_cookie.go
Normal file
35
internal/model/jd_cookie.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package model
|
||||
|
||||
import "kami/internal/consts"
|
||||
|
||||
// ====================================================================================
|
||||
// JD Cookie 相关模型结构体
|
||||
// ====================================================================================
|
||||
|
||||
// CreateOrderResult 创建订单返回结果
|
||||
type CreateOrderResult struct {
|
||||
WxPayUrl string `json:"wxPayUrl" dc:"微信支付链接"`
|
||||
JdOrderId string `json:"jdOrderId" dc:"京东订单号"`
|
||||
OrderId string `json:"orderId" dc:"内部订单号"`
|
||||
}
|
||||
|
||||
// PaymentResult 支付结果
|
||||
type PaymentResult struct {
|
||||
WxPayUrl string `json:"wxPayUrl" dc:"微信支付链接"`
|
||||
JdOrderId string `json:"jdOrderId" dc:"京东订单号"`
|
||||
OrderId string `json:"orderId" dc:"内部订单号"`
|
||||
}
|
||||
|
||||
// CreateNewJdOrderWithRetryReq 创建新的京东订单请求参数
|
||||
type CreateNewJdOrderWithRetryReq struct {
|
||||
OrderId string `json:"orderId" dc:"内部订单号"`
|
||||
Amount float64 `json:"amount" dc:"订单金额"`
|
||||
Category consts.RedeemOrderCardCategory `json:"category" dc:"卡券类别"`
|
||||
}
|
||||
|
||||
// CreateNewJdOrderWithRetryRes 创建新的京东订单返回结果
|
||||
type CreateNewJdOrderWithRetryRes struct {
|
||||
JdOrderId string `json:"jdOrderId" dc:"京东订单号"`
|
||||
CookieId string `json:"cookieId" dc:"Cookie ID"`
|
||||
WxPayUrl string `json:"wxPayUrl" dc:"微信支付链接"`
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"context"
|
||||
v1 "kami/api/jd_cookie/v1"
|
||||
"kami/internal/consts"
|
||||
"kami/internal/model"
|
||||
"kami/internal/model/entity"
|
||||
)
|
||||
|
||||
@@ -37,7 +38,7 @@ type (
|
||||
// GetJdOrderHistoryByOrderId 根据订单ID获取所有关联的京东订单历史
|
||||
GetJdOrderHistoryByOrderId(ctx context.Context, orderId string, page int, size int) (list []*v1.JdOrderHistoryInfo, total int, err error)
|
||||
// CreateOrder 创建订单
|
||||
CreateOrder(ctx context.Context, orderId string, amount float64, category consts.RedeemOrderCardCategory) (wxPayUrl string, jdOrderId string, err error)
|
||||
CreateOrder(ctx context.Context, userOrderId string, amount float64, category consts.RedeemOrderCardCategory) (result *model.CreateOrderResult, err error)
|
||||
// GetJdOrder 获取单个京东订单
|
||||
GetJdOrder(ctx context.Context, jdOrderId string) (order *v1.JdOrderInfo, err error)
|
||||
// ListJdOrder 京东订单列表查询
|
||||
@@ -55,7 +56,7 @@ type (
|
||||
// ReleaseExpiredJdOrders 释放过期京东订单的关联(使其可以被复用)
|
||||
ReleaseExpiredJdOrders(ctx context.Context) error
|
||||
// GetPaymentUrl 获取支付链接
|
||||
GetPaymentUrl(ctx context.Context, orderId string) (wxPayUrl string, jdOrderId string, err error)
|
||||
GetPaymentUrl(ctx context.Context, orderId string) (result *model.PaymentResult, err error)
|
||||
// GetOrder 获取单个订单
|
||||
GetOrder(ctx context.Context, orderId string) (order *v1.OrderInfo, err error)
|
||||
// GetOrderStatus 查询订单状态
|
||||
|
||||
@@ -104,7 +104,8 @@ func main() {
|
||||
`DROP TABLE IF EXISTS jd_cookie_order`,
|
||||
`CREATE TABLE jd_cookie_order (
|
||||
id bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
order_id varchar(64) NOT NULL COMMENT '订单号',
|
||||
order_id varchar(64) NOT NULL COMMENT '内部订单号',
|
||||
user_order_id varchar(64) DEFAULT NULL COMMENT '用户订单号',
|
||||
amount decimal(10,2) NOT NULL COMMENT '订单金额',
|
||||
category varchar(50) NOT NULL COMMENT '商品品类',
|
||||
jd_order_id varchar(64) DEFAULT NULL COMMENT '关联的京东订单号',
|
||||
@@ -116,6 +117,7 @@ func main() {
|
||||
deleted_at datetime DEFAULT NULL COMMENT '删除时间',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_order_id (order_id),
|
||||
KEY idx_user_order_id (user_order_id),
|
||||
KEY idx_status (status),
|
||||
KEY idx_jd_order_id (jd_order_id),
|
||||
KEY idx_last_request (last_request_at),
|
||||
|
||||
Reference in New Issue
Block a user