feat(jd_cookie): 新增风控失败状态及备注信息支持

- 新增风控失败状态枚举值 RiskFailed (300)- 在京东订单状态中增加 CkFailed 状态 (6) 及对应文案
- 为多个数据表添加 remark 字段用于存储备注信息
- 修改下单逻辑以支持风控失败重试机制
- 更新数据库表结构,将 remark 字段类型从 varchar(500) 改为 text
- 调整订单历史记录逻辑以包含备注信息-优化 Cookie 失效处理逻辑,支持风险控制失败场景
- 统一使用 GenerateRandomUUID生成订单号和历史记录 UUID- 完善订单状态变更历史记录,新增 ck_failed 变更类型
- 增加对京东接口返回 remark 信息的处理和支持
- 更新相关服务接口定义,添加 remark 参数传递
- 补充模型定义中的 remark 和 isCkFailed 字段映射
This commit is contained in:
danial
2025-10-17 18:17:56 +08:00
parent 924061810e
commit d812e1700b
22 changed files with 173 additions and 91 deletions

View File

@@ -43,6 +43,7 @@ type CookieHistoryInfo struct {
StatusAfter consts.JdCookieStatus `json:"statusAfter" dc:"变更后状态"`
UserOrderId string `json:"userOrderId" dc:"关联的订单号"`
FailureCount int `json:"failureCount" dc:"失败次数"`
Remark string `json:"remark" dc:"备注信息"`
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
}
@@ -66,5 +67,6 @@ type OrderHistoryInfo struct {
ChangeType consts.OrderChangeType `json:"changeType" dc:"变更类型"`
JdOrderId string `json:"jdOrderId" dc:"关联的京东订单号"`
WxPayUrl string `json:"wxPayUrl" dc:"微信支付链接"`
Remark string `json:"remark" dc:"备注信息"`
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
}

View File

@@ -190,6 +190,7 @@ type JdOrderHistoryInfo struct {
ChangeType consts.JdOrderChangeType `json:"changeType" dc:"变更类型create,bind,unbind,pay,expire,invalid,replace"`
OrderId string `json:"orderId" dc:"关联的订单号"`
WxPayUrl string `json:"wxPayUrl" dc:"微信支付链接"`
Remark string `json:"remark" dc:"备注信息"`
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
}

View File

@@ -36,7 +36,8 @@ const (
CardCookieJDStatusNormalFailed CardCookieJDOrderStatus = "failed" // 订单通用错误
CardCookieJDStatusCkFailed CardCookieJDOrderStatus = "ckFailed" // ck 错误
CardCookieJDStatusWrongFacePrice CardCookieJDOrderStatus = "wrongFacePrice"
CardCookieJDStatusExpired CardCookieJDOrderStatus = "expired"
CardCookieJDStatusExpired CardCookieJDOrderStatus = "expired" // 订单失效
CardCookieJDStatusRiskFailed CardCookieJDOrderStatus = "riskFailed" // 风险
)
type CardCookieUserClient string

View File

@@ -30,6 +30,7 @@ const (
JdOrderStatusSent JdOrderStatus = 3 // 已发货
JdOrderStatusExpired JdOrderStatus = 4 // 已过期
JdOrderStatusCanceled JdOrderStatus = 5 // 已取消
JdOrderStatusCkFailed JdOrderStatus = 6 // Cookie账号Ck失败
)
// JdOrderStatusText 京东订单状态文本映射
@@ -38,6 +39,8 @@ var JdOrderStatusText = map[JdOrderStatus]string{
JdOrderStatusPaid: "已支付",
JdOrderStatusExpired: "已过期",
JdOrderStatusCanceled: "已取消",
JdOrderStatusCkFailed: "Ck失败",
JdOrderStatusSent: "已发货",
}
// OrderStatus 订单状态枚举(与京东订单状态相同)
@@ -48,6 +51,7 @@ const (
OrderStatusPaid OrderStatus = 2 // 已支付
OrderStatusExpired OrderStatus = 3 // 已过期
OrderStatusCanceled OrderStatus = 4 // 已取消
OrderStatusCkFailed OrderStatus = 5 // Cookie账号Ck失败
)
// OrderStatusText 订单状态文本映射
@@ -56,6 +60,7 @@ var OrderStatusText = map[OrderStatus]string{
OrderStatusPaid: "已支付",
OrderStatusExpired: "已过期",
OrderStatusCanceled: "已取消",
OrderStatusCkFailed: "cookie失效",
}
// ====================================================================================
@@ -105,18 +110,20 @@ var JdOrderChangeTypeText = map[JdOrderChangeType]string{
type OrderChangeType string
const (
OrderChangeTypeCreate OrderChangeType = "create" // 创建
OrderChangeTypePay OrderChangeType = "pay" // 支付
OrderChangeTypeExpire OrderChangeType = "expire" // 过期
OrderChangeTypeRebind OrderChangeType = "rebind" // 重新绑定
OrderChangeTypeCreate OrderChangeType = "create" // 创建
OrderChangeTypePay OrderChangeType = "pay" // 支付
OrderChangeTypeExpire OrderChangeType = "expire" // 过期
OrderChangeTypeRebind OrderChangeType = "rebind" // 重新绑定
OrderChangeTypeCkFailed OrderChangeType = "ck_failed" // Cookie账号Ck失败
)
// OrderChangeTypeText 订单变更类型文本映射
var OrderChangeTypeText = map[OrderChangeType]string{
OrderChangeTypeCreate: "创建",
OrderChangeTypePay: "支付",
OrderChangeTypeExpire: "过期",
OrderChangeTypeRebind: "重新绑定",
OrderChangeTypeCreate: "创建",
OrderChangeTypePay: "支付",
OrderChangeTypeExpire: "过期",
OrderChangeTypeRebind: "重新绑定",
OrderChangeTypeCkFailed: "cookie失败",
}
// ====================================================================================

View File

@@ -30,6 +30,7 @@ type V1JdCookieJdOrderChangeHistoryColumns struct {
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 删除时间
Remark string // 备注信息
}
// v1JdCookieJdOrderChangeHistoryColumns holds the columns for the table jd_cookie_jd_order_change_history.
@@ -43,6 +44,7 @@ var v1JdCookieJdOrderChangeHistoryColumns = V1JdCookieJdOrderChangeHistoryColumn
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
Remark: "remark",
}
// NewV1JdCookieJdOrderChangeHistoryDao creates and returns a new DAO object for table data access.

View File

@@ -29,6 +29,7 @@ type V1JdCookieOrderChangeHistoryColumns struct {
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 删除时间
Remark string // 备注信息
}
// v1JdCookieOrderChangeHistoryColumns holds the columns for the table jd_cookie_order_change_history.
@@ -41,6 +42,7 @@ var v1JdCookieOrderChangeHistoryColumns = V1JdCookieOrderChangeHistoryColumns{
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
Remark: "remark",
}
// NewV1JdCookieOrderChangeHistoryDao creates and returns a new DAO object for table data access.

View File

@@ -56,6 +56,7 @@ func (s *sJdCookie) GetCookieHistory(ctx context.Context, cookieId string, page,
StatusAfter: consts.JdCookieStatus(gconv.Int(history.StatusAfter)),
UserOrderId: history.UserOrderId,
FailureCount: gconv.Int(history.FailureCount),
Remark: history.Remark,
CreatedAt: history.CreatedAt,
}
list = append(list, info)
@@ -107,6 +108,7 @@ func (s *sJdCookie) getUserOrderHistory(ctx context.Context, orderId string, pag
OrderId: history.OrderId,
ChangeType: consts.OrderChangeType(history.ChangeType),
JdOrderId: history.JdOrderId,
Remark: history.Remark,
CreatedAt: history.CreatedAt,
}
list = append(list, info)
@@ -142,6 +144,7 @@ func (s *sJdCookie) getJdOrderHistory(ctx context.Context, jdOrderId string, pag
ChangeType: consts.OrderChangeType(history.ChangeType),
JdOrderId: history.JdOrderId,
WxPayUrl: history.WxPayUrl,
Remark: history.Remark,
CreatedAt: history.CreatedAt,
}
list = append(list, info)
@@ -187,6 +190,7 @@ func (s *sJdCookie) GetJdOrderHistoryByJdOrderId(ctx context.Context, jdOrderId
ChangeType: consts.JdOrderChangeType(history.ChangeType),
OrderId: history.OrderId,
WxPayUrl: history.WxPayUrl,
Remark: history.Remark,
CreatedAt: history.CreatedAt,
}
list = append(list, info)

View File

@@ -73,7 +73,6 @@ func (s *sJdCookie) CreateOrder(ctx context.Context, userOrderId string, amount
var cookieId, jdOrderId, wxPayUrl string
var isReused = false
if reusableJdOrder != nil {
// 尝试使用可复用的京东订单
jdOrderId = reusableJdOrder.JdOrderId
@@ -83,19 +82,21 @@ func (s *sJdCookie) CreateOrder(ctx context.Context, userOrderId string, amount
// 检查支付链接是否过期
if reusableJdOrder.WxPayExpireAt != nil && gtime.Now().After(reusableJdOrder.WxPayExpireAt) {
// 支付链接已过期,尝试刷新
newWxPayUrl, refreshErr := s.refreshPaymentUrl(ctx, &model.RefreshPaymentUrlReq{
newWxPayUrl, isCkFailed, refreshErr := s.refreshPaymentUrl(ctx, &model.RefreshPaymentUrlReq{
JdOrderId: jdOrderId,
PayId: reusableJdOrder.PayId,
CookieId: cookieId,
})
if isCkFailed {
s.handleCookieFailure(ctx, cookieId, jdOrderId, isCkFailed, refreshErr.Error())
}
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)
_ = s.UpdateJdOrderStatus(ctx, jdOrderId, consts.JdOrderStatusExpired, "", refreshErr.Error())
// 记录Cookie刷新失败历史
_ = s.RecordCookieHistory(ctx, &model.RecordCookieHistoryReq{
@@ -206,11 +207,13 @@ func (s *sJdCookie) createNewJdOrderWithRetry(ctx context.Context, req *model.Cr
// 记录已尝试的Cookie
triedCookies = append(triedCookies, availableCookieId)
jdOrderId := utils.GenerateRandomUUID()
// 调用京东下单接口
createOrderRes, lastErr := s.callJdCreateOrder(ctx, &model.CallJdCreateOrderReq{
CookieId: availableCookieId,
Amount: req.Amount,
Category: req.Category,
JdOrderId: jdOrderId,
CookieId: availableCookieId,
Amount: req.Amount,
Category: req.Category,
})
if lastErr != nil {
glog.Warning(ctx, "京东下单失败尝试切换Cookie重试", g.Map{
@@ -219,9 +222,15 @@ func (s *sJdCookie) createNewJdOrderWithRetry(ctx context.Context, req *model.Cr
"triedCookies": len(triedCookies),
"error": lastErr,
})
isCkFailed := false
remark := ""
if createOrderRes != nil {
remark = createOrderRes.Remark
isCkFailed = createOrderRes.IsCkFailed
}
// Cookie失败更新状态
s.handleCookieFailure(ctx, availableCookieId, req.OrderId)
s.handleCookieFailure(ctx, availableCookieId, "", isCkFailed, remark)
// 继续下一次重试
continue
@@ -229,7 +238,7 @@ func (s *sJdCookie) createNewJdOrderWithRetry(ctx context.Context, req *model.Cr
// 下单成功,创建京东订单记录
err = s.createJdOrderRecord(ctx, &model.CreateJdOrderRecordReq{
JdOrderId: createOrderRes.JdOrderId, // 内部订单号
JdOrderId: jdOrderId, // 内部订单号
RealJdOrderId: createOrderRes.RealJdOrderId, // 京东客户端返回的真实订单ID
PayId: createOrderRes.PayId,
CookieId: availableCookieId,
@@ -239,25 +248,25 @@ func (s *sJdCookie) createNewJdOrderWithRetry(ctx context.Context, req *model.Cr
})
if err != nil {
glog.Error(ctx, "创建京东订单记录失败", g.Map{
"jdOrderId": createOrderRes.JdOrderId,
"jdOrderId": jdOrderId,
"error": err,
})
return nil, gerror.Wrap(err, "创建京东订单记录失败")
}
// 记录京东订单创建历史
_ = s.RecordJdOrderHistory(ctx, createOrderRes.JdOrderId, consts.JdOrderChangeTypeCreate, req.OrderId, createOrderRes.WxPayUrl)
_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypeCreate, req.OrderId, createOrderRes.WxPayUrl, "")
glog.Info(ctx, "创建京东订单成功", g.Map{
"orderId": req.OrderId,
"jdOrderId": createOrderRes.JdOrderId,
"jdOrderId": jdOrderId,
"cookieId": availableCookieId,
"triedCookies": len(triedCookies),
})
// 返回成功结果
return &model.CreateNewJdOrderWithRetryRes{
JdOrderId: createOrderRes.JdOrderId,
JdOrderId: jdOrderId,
CookieId: availableCookieId,
WxPayUrl: createOrderRes.WxPayUrl,
}, nil

View File

@@ -459,6 +459,14 @@ func (s *sJdCookie) ExtractCardInfo(ctx context.Context, jdOrderId string) error
return nil
}
// 记录卡密提取历史
var order *entity.V1JdCookieOrder
if jdOrder.CurrentOrderId > 0 {
_ = dao.V1JdCookieOrder.Ctx(ctx).DB(config.GetDatabaseV1()).
Where(dao.V1JdCookieOrder.Columns().Id, jdOrder.CurrentOrderId).
Scan(&order)
}
// 获取Cookie信息
cookieInfo, err := s.getCookieById(ctx, jdOrder.CookieId)
if err != nil || cookieInfo == nil {
@@ -472,15 +480,20 @@ func (s *sJdCookie) ExtractCardInfo(ctx context.Context, jdOrderId string) error
Category: consts.RedeemOrderCardCategory(jdOrder.Category),
})
if err != nil {
return gerror.Wrap(err, "查询订单支付状态失败")
}
// 记录卡密提取历史
var order *entity.V1JdCookieOrder
if jdOrder.CurrentOrderId > 0 {
_ = dao.V1JdCookieOrder.Ctx(ctx).DB(config.GetDatabaseV1()).
Where(dao.V1JdCookieOrder.Columns().Id, jdOrder.CurrentOrderId).
Scan(&order)
if resp != nil {
if resp.IsCkFailed {
s.handleCookieFailure(ctx, cookieInfo.CookieId, jdOrderId, true, resp.Remark)
_ = s.UpdateJdOrderStatus(ctx, jdOrderId, consts.JdOrderStatusCkFailed, "", resp.Remark)
if order != nil {
_, _ = dao.V1JdCookieOrder.Ctx(ctx).DB(config.GetDatabaseV1()).Where(dao.V1JdCookieOrder.Columns().Id, order.Id).
Update(do.V1JdCookieOrder{
Status: consts.OrderStatusCkFailed,
})
_ = s.RecordOrderHistory(ctx, order.OrderId, consts.OrderChangeTypeCkFailed, jdOrderId)
}
}
}
return gerror.Wrap(err, "查询京东订单支付状态失败")
}
if !slices.Contains([]string{"待使用", "待发送"}, resp.OrderStatus) {
@@ -495,7 +508,7 @@ func (s *sJdCookie) ExtractCardInfo(ctx context.Context, jdOrderId string) error
Status: consts.JdOrderStatusPaid,
})
if order != nil {
_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypePay, order.OrderId, jdOrder.WxPayUrl)
_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypePay, order.OrderId, jdOrder.WxPayUrl, "")
_, _ = dao.V1JdCookieOrder.Ctx(ctx).DB(config.GetDatabaseV1()).Where(dao.V1JdCookieOrder.Columns().Id, order.Id).
Update(do.V1JdCookieOrder{
Status: consts.OrderStatusPaid,
@@ -528,7 +541,7 @@ func (s *sJdCookie) ExtractCardInfo(ctx context.Context, jdOrderId string) error
return gerror.Wrap(err, "保存卡密信息失败")
}
_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypeSend, order.OrderId, jdOrder.WxPayUrl)
_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypeSend, order.OrderId, jdOrder.WxPayUrl, "")
//提取成功要回调
go s.Callback(ctx, order.OrderId, order.UserOrderId, order.Amount.InexactFloat64())
@@ -620,7 +633,7 @@ func (s *sJdCookie) CleanupExpiredOrders(ctx context.Context) error {
_ = s.RecordOrderHistory(ctx, orderId, consts.OrderChangeTypeExpire, jdOrder.JdOrderId)
}
}
_ = s.RecordJdOrderHistory(ctx, jdOrder.JdOrderId, consts.JdOrderChangeTypeExpire, orderId, jdOrder.WxPayUrl)
_ = s.RecordJdOrderHistory(ctx, jdOrder.JdOrderId, consts.JdOrderChangeTypeExpire, orderId, jdOrder.WxPayUrl, "")
}
// 清理过期的用户订单

View File

@@ -43,16 +43,19 @@ func (s *sJdCookie) GetPaymentUrl(ctx context.Context, orderId string) (result *
// 检查支付链接是否有效
if jdOrder.WxPayExpireAt != nil && gtime.Now().After(jdOrder.WxPayExpireAt) {
// 支付链接已过期,尝试刷新
newWxPayUrl, refreshErr := s.refreshPaymentUrl(ctx, &model.RefreshPaymentUrlReq{
// 刷新京东订单
newWxPayUrl, isCkFailed, refreshErr := s.refreshPaymentUrl(ctx, &model.RefreshPaymentUrlReq{
JdOrderId: jdOrder.JdOrderId,
PayId: jdOrder.PayId,
CookieId: jdOrder.CookieId,
})
if isCkFailed {
s.handleCookieFailure(ctx, jdOrder.CookieId, jdOrder.JdOrderId, isCkFailed, "获取支付链接失败")
}
if refreshErr != nil {
// 刷新失败,标记旧订单为失效
_ = s.UpdateJdOrderStatus(ctx, jdOrder.JdOrderId, consts.JdOrderStatusExpired, "刷新支付链接失败")
_ = s.RecordJdOrderHistory(ctx, jdOrder.JdOrderId, consts.JdOrderChangeTypeInvalid, orderId, jdOrder.WxPayUrl)
_ = s.UpdateJdOrderStatus(ctx, jdOrder.JdOrderId, consts.JdOrderStatusExpired, jdOrder.WxPayUrl, refreshErr.Error())
_ = s.RecordCookieHistory(ctx, &model.RecordCookieHistoryReq{
CookieId: jdOrder.CookieId,
ChangeType: consts.CookieChangeTypeRefreshFail,

View File

@@ -163,7 +163,7 @@ func (s *sJdCookie) updateJdOrderPaymentUrl(ctx context.Context, jdOrderId, wxPa
orderId = order.OrderId
}
}
_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypeSend, orderId, wxPayUrl)
_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypeSend, orderId, wxPayUrl, "")
}
return err
@@ -193,7 +193,7 @@ func (s *sJdCookie) updateJdOrderCurrentOrderId(ctx context.Context, jdOrderId,
// 记录解绑历史
if oldJdOrder != nil && oldJdOrder.CurrentOrderId > 0 {
_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypeUnbind, "", oldJdOrder.WxPayUrl)
_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypeUnbind, "", oldJdOrder.WxPayUrl, "")
}
return nil
@@ -240,7 +240,7 @@ func (s *sJdCookie) updateJdOrderCurrentOrderId(ctx context.Context, jdOrderId,
if oldJdOrder != nil {
wxPayUrl = oldJdOrder.WxPayUrl
}
_ = s.RecordJdOrderHistory(ctx, jdOrderId, changeType, orderId, wxPayUrl)
_ = s.RecordJdOrderHistory(ctx, jdOrderId, changeType, orderId, wxPayUrl, "")
return err
}
@@ -276,28 +276,32 @@ func (s *sJdCookie) findReusableJdOrder(ctx context.Context, amount float64, cat
// callJdCreateOrder 调用京东下单接口
func (s *sJdCookie) callJdCreateOrder(ctx context.Context, req *model.CallJdCreateOrderReq) (res *model.CallJdCreateOrderRes, err error) {
res = &model.CallJdCreateOrderRes{
IsCkFailed: false,
}
cookie, err := s.getCookieById(ctx, req.CookieId)
if err != nil {
return
}
jdOrderId := utils.GenerateRandomUUID()
appResp, err := originalJd.NewClient().AppleRecharge(ctx, &originalJd.AppleRechargeReq{
FacePrice: req.Amount,
Category: req.Category,
OrderNum: jdOrderId,
OrderNum: req.JdOrderId,
Cookies: cookie.CookieValue,
})
glog.Info(ctx, "下单接口返回", appResp)
if err != nil {
return
}
if appResp.Code != consts.CardCookieJDStatusSuccess || appResp.Deeplink == "" {
return nil, gerror.New("下单失败," + appResp.Msg)
res.Remark = appResp.Msg
if appResp.Code == consts.CardCookieJDStatusCkFailed {
res.IsCkFailed = true
return res, gerror.New("Cookie已失效")
}
if appResp.Code != consts.CardCookieJDStatusSuccess || appResp.Deeplink == "" {
return res, gerror.New("下单失败," + appResp.Msg)
}
res = &model.CallJdCreateOrderRes{
JdOrderId: jdOrderId, // 内部订单号
RealJdOrderId: appResp.OrderId, // 京东客户端返回的真实订单ID
PayId: appResp.PayId,
WxPayUrl: appResp.Deeplink,
@@ -306,7 +310,7 @@ func (s *sJdCookie) callJdCreateOrder(ctx context.Context, req *model.CallJdCrea
}
// refreshPaymentUrl 刷新支付链接
func (s *sJdCookie) refreshPaymentUrl(ctx context.Context, req *model.RefreshPaymentUrlReq) (wxPayUrl string, err error) {
func (s *sJdCookie) refreshPaymentUrl(ctx context.Context, req *model.RefreshPaymentUrlReq) (wxPayUrl string, isCkFailed bool, err error) {
cookie, err := s.getCookieById(ctx, req.CookieId)
if err != nil {
return
@@ -332,8 +336,11 @@ func (s *sJdCookie) refreshPaymentUrl(ctx context.Context, req *model.RefreshPay
if err != nil {
return
}
if appResp.Code == consts.CardCookieJDStatusExpired {
return "", true, gerror.New(appResp.Msg)
}
if appResp.Code != consts.CardCookieJDStatusSuccess || appResp.Deeplink == "" {
return "", gerror.New("刷新失败" + appResp.Msg)
return "", false, gerror.New("刷新链接" + appResp.Msg)
}
wxPayUrl = appResp.Deeplink
return
@@ -346,7 +353,7 @@ func (s *sJdCookie) callJdCheckPayment(ctx context.Context, req *model.CallJdChe
// 调用检查支付状态接口使用京东客户端返回的真实订单ID
appReq := &originalJd.AppleRechargeCardInfoReq{
OrderId: utils.GenerateRandomUUID(),
OrderId: req.JdOrderId,
JdOrderId: req.RealJdOrderId,
Cookies: req.CookieValue,
Category: req.Category,
@@ -358,7 +365,7 @@ func (s *sJdCookie) callJdCheckPayment(ctx context.Context, req *model.CallJdChe
"realJdOrderId": req.RealJdOrderId,
"error": err,
})
return nil, err
return resp, err
}
glog.Info(ctx, "京东检查支付状态成功", resp)
@@ -371,7 +378,7 @@ func (s *sJdCookie) callJdCheckPayment(ctx context.Context, req *model.CallJdChe
// ====================================================================================
// handleCookieFailure 处理Cookie失败
func (s *sJdCookie) handleCookieFailure(ctx context.Context, cookieId, orderId string) {
func (s *sJdCookie) handleCookieFailure(ctx context.Context, cookieId, orderId string, isCKFailed bool, remark string) {
// 获取当前Cookie信息
m := dao.V1JdCookieAccount.Ctx(ctx).DB(config.GetDatabaseV1())
var account *entity.V1JdCookieAccount
@@ -384,7 +391,7 @@ func (s *sJdCookie) handleCookieFailure(ctx context.Context, cookieId, orderId s
statusBefore := consts.JdCookieStatus(account.Status)
var statusAfter consts.JdCookieStatus
if newFailureCount >= consts.JdCookieMaxFailureCount {
if newFailureCount >= consts.JdCookieMaxFailureCount || isCKFailed {
// 失败次数过多,标记为失效
statusAfter = consts.JdCookieStatusExpired
_, _ = m.Where(dao.V1JdCookieAccount.Columns().CookieId, cookieId).Update(&do.V1JdCookieAccount{
@@ -410,5 +417,6 @@ func (s *sJdCookie) handleCookieFailure(ctx context.Context, cookieId, orderId s
StatusAfter: statusAfter,
UserOrderId: orderId,
FailureCount: newFailureCount,
Remark: remark,
})
}

View File

@@ -15,7 +15,6 @@ import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/guid"
)
// ====================================================================================
@@ -199,13 +198,13 @@ func (s *sJdCookie) CreateJdOrder(ctx context.Context, jdOrderId, payId, cookieI
}
// 记录京东订单创建历史
_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypeCreate, payId, "")
_ = s.RecordJdOrderHistory(ctx, jdOrderId, consts.JdOrderChangeTypeCreate, payId, "", "")
return
}
// UpdateJdOrderStatus 更新京东订单状态
func (s *sJdCookie) UpdateJdOrderStatus(ctx context.Context, jdOrderId string, status consts.JdOrderStatus, wxPayUrl string) (err error) {
func (s *sJdCookie) UpdateJdOrderStatus(ctx context.Context, jdOrderId string, status consts.JdOrderStatus, wxPayUrl string, remark string) (err error) {
if jdOrderId == "" {
return gerror.New("京东订单号不能为空")
}
@@ -246,6 +245,8 @@ func (s *sJdCookie) UpdateJdOrderStatus(ctx context.Context, jdOrderId string, s
changeType = consts.JdOrderChangeTypeExpire
case consts.JdOrderStatusCanceled:
changeType = consts.JdOrderChangeTypeInvalid
case consts.JdOrderStatusCkFailed:
changeType = consts.JdOrderChangeTypeInvalid
default:
changeType = consts.JdOrderChangeTypeSend
}
@@ -267,7 +268,7 @@ func (s *sJdCookie) UpdateJdOrderStatus(ctx context.Context, jdOrderId string, s
if payUrl == "" {
payUrl = oldOrder.WxPayUrl
}
_ = s.RecordJdOrderHistory(ctx, jdOrderId, changeType, orderId, payUrl)
_ = s.RecordJdOrderHistory(ctx, jdOrderId, changeType, orderId, payUrl, remark)
}
return
@@ -310,16 +311,16 @@ func (s *sJdCookie) RecordCookieHistory(ctx context.Context, req *model.RecordCo
}
// RecordJdOrderHistory 记录京东订单变更历史
func (s *sJdCookie) RecordJdOrderHistory(ctx context.Context, jdOrderId string, changeType consts.JdOrderChangeType, orderId, wxPayUrl string) (err error) {
func (s *sJdCookie) RecordJdOrderHistory(ctx context.Context, jdOrderId string, changeType consts.JdOrderChangeType, orderId, wxPayUrl, remark string) (err error) {
m := dao.V1JdCookieJdOrderChangeHistory.Ctx(ctx).DB(config.GetDatabaseV1())
historyUuid := guid.S()
_, err = m.Insert(&do.V1JdCookieJdOrderChangeHistory{
HistoryUuid: historyUuid,
HistoryUuid: utils.GenerateRandomUUID(),
JdOrderId: jdOrderId,
ChangeType: changeType,
OrderId: orderId,
WxPayUrl: wxPayUrl,
Remark: remark,
})
if err != nil {
@@ -338,7 +339,7 @@ func (s *sJdCookie) RecordJdOrderHistory(ctx context.Context, jdOrderId string,
func (s *sJdCookie) RecordOrderHistory(ctx context.Context, orderId string, changeType consts.OrderChangeType, jdOrderId string) (err error) {
m := dao.V1JdCookieOrderChangeHistory.Ctx(ctx).DB(config.GetDatabaseV1())
historyUuid := guid.S()
historyUuid := utils.GenerateRandomUUID()
_, err = m.Insert(&do.V1JdCookieOrderChangeHistory{
HistoryUuid: historyUuid,
OrderId: orderId,

View File

@@ -21,4 +21,5 @@ type V1JdCookieJdOrderChangeHistory struct {
CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 更新时间
DeletedAt *gtime.Time // 删除时间
Remark any // 备注信息
}

View File

@@ -20,4 +20,5 @@ type V1JdCookieOrderChangeHistory struct {
CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 更新时间
DeletedAt *gtime.Time // 删除时间
Remark any // 备注信息
}

View File

@@ -19,4 +19,5 @@ type V1JdCookieJdOrderChangeHistory struct {
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"`
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"删除时间"`
Remark string `json:"remark" orm:"remark" description:"备注信息"`
}

View File

@@ -18,4 +18,5 @@ type V1JdCookieOrderChangeHistory struct {
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"`
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"删除时间"`
Remark string `json:"remark" orm:"remark" description:"备注信息"`
}

View File

@@ -47,17 +47,19 @@ type CreateJdOrderRecordReq struct {
// CallJdCreateOrderReq 调用京东下单接口请求参数
type CallJdCreateOrderReq struct {
CookieId string `json:"cookieId" dc:"Cookie ID"`
Amount float64 `json:"amount" dc:"订单金额"`
Category consts.RedeemOrderCardCategory `json:"category" dc:"商品品类"`
JdOrderId string `json:"jdOrderId" dc:"京东订单ID"`
Amount float64 `json:"amount" dc:"订单金额"`
CookieId string `json:"cookieId" dc:"Cookie ID"`
Category consts.RedeemOrderCardCategory `json:"category" dc:"商品品类"`
}
// CallJdCreateOrderRes 调用京东下单接口返回结果
type CallJdCreateOrderRes struct {
JdOrderId string `json:"jdOrderId" dc:"内部订单号"`
RealJdOrderId string `json:"realJdOrderId" dc:"京东客户端返回的真实订单ID"`
PayId string `json:"payId" dc:"支付ID"`
WxPayUrl string `json:"wxPayUrl" dc:"微信支付链接"`
Remark string `json:"remark" dc:"备注信息"`
IsCkFailed bool `json:"isCkFailed" dc:"Cookie是否失败"`
}
// RefreshPaymentUrlReq 刷新支付链接请求参数

View File

@@ -49,6 +49,8 @@ type (
BatchCheckPaymentStatus(ctx context.Context) error
// ExtractCardInfo 提取卡密信息
ExtractCardInfo(ctx context.Context, jdOrderId string) error
// Callback TODO:临时的回调
Callback(ctx context.Context, orderId string, userOrderId string, amount float64)
// ShouldExtractCard 判断是否需要提取卡密
ShouldExtractCard(ctx context.Context, jdOrder *entity.V1JdCookieJdOrder) bool
// CleanupExpiredOrders 清理过期订单(定时任务)
@@ -72,11 +74,11 @@ type (
// CreateJdOrder 创建京东订单
CreateJdOrder(ctx context.Context, jdOrderId string, payId string, cookieId string, category string, amount float64) (err error)
// UpdateJdOrderStatus 更新京东订单状态
UpdateJdOrderStatus(ctx context.Context, jdOrderId string, status consts.JdOrderStatus, wxPayUrl string) (err error)
UpdateJdOrderStatus(ctx context.Context, jdOrderId string, status consts.JdOrderStatus, wxPayUrl string, remark string) (err error)
// RecordCookieHistory 记录Cookie变更历史
RecordCookieHistory(ctx context.Context, req *model.RecordCookieHistoryReq) (err error)
// RecordJdOrderHistory 记录京东订单变更历史
RecordJdOrderHistory(ctx context.Context, jdOrderId string, changeType consts.JdOrderChangeType, orderId string, wxPayUrl string) (err error)
RecordJdOrderHistory(ctx context.Context, jdOrderId string, changeType consts.JdOrderChangeType, orderId string, wxPayUrl string, remark string) (err error)
// RecordOrderHistory 记录订单变更历史
RecordOrderHistory(ctx context.Context, orderId string, changeType consts.OrderChangeType, jdOrderId string) (err error)
}

View File

@@ -15,7 +15,7 @@ CREATE TABLE `jd_cookie_account` (
`failure_count` int DEFAULT 0 COMMENT '连续失败次数',
`last_used_at` datetime DEFAULT NULL COMMENT '最后使用时间',
`suspend_until` datetime DEFAULT NULL COMMENT '暂停解除时间',
`remark` varchar(500) DEFAULT NULL COMMENT '备注信息',
`remark` text DEFAULT NULL COMMENT '备注信息',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted_at` datetime DEFAULT NULL COMMENT '删除时间',
@@ -93,6 +93,7 @@ CREATE TABLE `jd_cookie_change_history` (
`status_after` tinyint DEFAULT NULL COMMENT '变更后状态',
`user_order_id` varchar(64) DEFAULT NULL COMMENT '关联的订单号',
`failure_count` int DEFAULT NULL COMMENT '失败次数',
`remark` text DEFAULT NULL COMMENT '备注信息',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted_at` datetime DEFAULT NULL COMMENT '删除时间',
@@ -114,6 +115,7 @@ CREATE TABLE `jd_cookie_jd_order_change_history` (
`change_type` varchar(20) NOT NULL COMMENT '变更类型create,bind,unbind,pay,expire,invalid,replace',
`order_id` varchar(64) DEFAULT NULL COMMENT '关联的订单号',
`wx_pay_url` text DEFAULT NULL COMMENT '微信支付链接',
`remark` text DEFAULT NULL COMMENT '备注信息',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted_at` datetime DEFAULT NULL COMMENT '删除时间',
@@ -134,6 +136,7 @@ CREATE TABLE `jd_cookie_order_change_history` (
`order_id` varchar(64) NOT NULL COMMENT '订单号',
`change_type` varchar(20) NOT NULL COMMENT '变更类型create,bind,pay,expire,rebind',
`jd_order_id` varchar(64) DEFAULT NULL COMMENT '关联的京东订单号',
`remark` text DEFAULT NULL COMMENT '备注信息',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted_at` datetime DEFAULT NULL COMMENT '删除时间',

View File

@@ -10,27 +10,38 @@ import (
// AppleRecharge 所有权益充值——下单接口
func (c *Client) AppleRecharge(ctx context.Context, input *AppleRechargeReq) (*AppleRechargeResp, error) {
resp := &AppleRechargeResp{}
var resp = &AppleRechargeResp{}
glog.Info(ctx, "苹果权益充值", input)
response, err := c.Client.ContentJson().Post(ctx, "http://jd_babel_channel:8289/jd/app/store", input)
if err != nil {
return resp, err
}
respData := response.ReadAllString()
clientResp := AppleRechargeClientResp{}
err = json.Unmarshal([]byte(respData), &clientResp)
if err != nil {
glog.Error(ctx, "获取信息失败", respData, err)
return resp, err
for range 3 {
response, err := c.Client.ContentJson().Post(ctx, "http://jd_babel_channel:8289/jd/app/store", input)
if err != nil {
return resp, err
}
respData := response.ReadAllString()
clientResp := AppleRechargeClientResp{}
err = json.Unmarshal([]byte(respData), &clientResp)
if err != nil {
glog.Error(ctx, "获取信息失败", respData, err)
return resp, err
}
resp = &AppleRechargeResp{
Code: clientResp.Code.JDOrderStatus(),
Deeplink: clientResp.Data.Deeplink,
OrderId: clientResp.Data.OrderId.String(),
PayId: clientResp.Data.PayId,
Msg: clientResp.Data.Remark,
}
if clientResp.Code == RiskFailed {
continue
}
if clientResp.Code != Success {
return resp, gerror.New("苹果权益充值失败")
}
break
}
resp = &AppleRechargeResp{
Code: clientResp.Code.JDOrderStatus(),
Deeplink: clientResp.Data.Deeplink,
OrderId: clientResp.Data.OrderId.String(),
PayId: clientResp.Data.PayId,
}
if clientResp.Code != Success {
if resp == nil {
return resp, gerror.New("苹果权益充值失败")
}
return resp, nil
@@ -46,6 +57,7 @@ func (c *Client) GetCardInfo(ctx context.Context, input *AppleRechargeCardInfoRe
Code int `json:"code"`
Msg string `json:"msg"`
Data struct {
Remark string `json:"remark"`
CardPwd string `json:"card_pwd"`
CardNo string `json:"card_num"`
OrderStatus string `json:"order_status"`
@@ -56,15 +68,16 @@ func (c *Client) GetCardInfo(ctx context.Context, input *AppleRechargeCardInfoRe
if err != nil {
return
}
if clientResp.Code != 100 || clientResp.Data.CardNo == "" {
err = gerror.New("获取卡号、卡密失败")
return
}
resp = &AppleRechargeCardInfoResp{
OrderStatus: clientResp.Data.OrderStatus,
Remark: clientResp.Data.Remark,
CardNo: clientResp.Data.CardNo,
IsCkFailed: clientResp.Code == int(CkFailed),
CardPassword: clientResp.Data.CardPwd,
}
if clientResp.Code != int(Success) || clientResp.Data.CardNo == "" {
return resp, gerror.New("状态不正确")
}
return
}
@@ -87,6 +100,7 @@ func (c *Client) RefreshPayment(ctx context.Context, input *RefreshPaymentReq) (
Deeplink: clientResp.Data.Deeplink,
OrderId: clientResp.Data.OrderId.String(),
PayId: clientResp.Data.PayId,
Msg: clientResp.Data.Remark,
}
if clientResp.Code != Success {
return resp, gerror.New("苹果权益充值失败")

View File

@@ -14,6 +14,7 @@ const (
OrderTypeNotSupported HttpStatus = 203 // 不支持的订单类型
OrderExpired HttpStatus = 204 // 订单过期
InternalError HttpStatus = 500 // 内部错误
RiskFailed HttpStatus = 300 // 风控失败
)
// String 方法用于返回枚举值的名称

View File

@@ -60,6 +60,7 @@ type AppleRechargeClientResp struct {
Deeplink string `json:"deeplink"`
OrderId json.Number `json:"order_id"`
PayId string `json:"pay_id"`
Remark string `json:"remark,omitempty"`
} `json:"data,omitempty"`
}
@@ -83,6 +84,8 @@ type AppleRechargeCardInfoResp struct {
OrderStatus string `json:"order_status"`
CardNo string `json:"cardNo"`
CardPassword string `json:"cardPassword"`
Remark string `json:"remark"`
IsCkFailed bool `json:"is_ck_failed"`
}
type QueryCardReq struct {