- 新增CamelOilToken和CamelOilCardBinding数据库表,实现Token及卡密绑定记录管理 - 在service层增加Token的创建、查询、更新、删除及分页功能 - 实现卡密与Token绑定的业务逻辑,支持基于Token的卡密管理 - 在API层新增Token和卡密绑定相关接口:创建Token、获取Token详情、删除Token、列出Token及根据Token查询绑定卡密 - camel_oil_api新增绑卡接口,支持绑卡状态分类及错误处理 - 在定时任务中增加卡密绑定任务,实现自动处理已支付订单的卡密绑定 - 优化订单提交及支付流程,包含日志调整和请求参数随机扰动 - 统一调整camel_oil模块多控制器实现,完成账号状态查询及订单相关接口实现 - 注册更多camel_oil定时任务,包括订单支付检查、账号日重置和待回调订单处理任务
178 lines
5.7 KiB
Go
178 lines
5.7 KiB
Go
package camel_oil
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
v1 "kami/api/camel_oil/v1"
|
|
"kami/internal/consts"
|
|
"kami/internal/dao"
|
|
"kami/internal/model/do"
|
|
"kami/internal/model/entity"
|
|
"kami/utility/config"
|
|
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
"github.com/gogf/gf/v2/net/gclient"
|
|
"github.com/gogf/gf/v2/os/glog"
|
|
)
|
|
|
|
// ====================================================================================
|
|
// 订单回调逻辑
|
|
// ====================================================================================
|
|
|
|
// updateCallbackResult 更新回调结果(内部方法)
|
|
func (s *sCamelOil) updateCallbackResult(ctx context.Context, order *entity.V1CamelOilOrder, success bool, historyDesc string) error {
|
|
m := dao.V1CamelOilOrder.Ctx(ctx).DB(config.GetDatabaseV1())
|
|
|
|
if success {
|
|
// 回调成功
|
|
_, err := m.Where(dao.V1CamelOilOrder.Columns().Id, order.Id).Update(&do.V1CamelOilOrder{
|
|
NotifyStatus: consts.CamelOilCallbackStatusSuccess,
|
|
NotifyCount: order.NotifyCount + 1,
|
|
})
|
|
|
|
if err != nil {
|
|
return gerror.Wrap(err, "更新回调成功状态失败")
|
|
}
|
|
|
|
_ = s.RecordOrderHistory(ctx, order.OrderNo, consts.CamelOilOrderChangeTypeCallbackSuccess, "", historyDesc)
|
|
} else {
|
|
// 回调失败
|
|
notifyCount := order.NotifyCount + 1
|
|
notifyStatus := consts.CamelOilCallbackStatusPending
|
|
if notifyCount >= 3 {
|
|
notifyStatus = consts.CamelOilCallbackStatusFailed
|
|
}
|
|
|
|
_, err := m.Where(dao.V1CamelOilOrder.Columns().Id, order.Id).Update(&do.V1CamelOilOrder{
|
|
NotifyStatus: notifyStatus,
|
|
NotifyCount: notifyCount,
|
|
})
|
|
|
|
if err != nil {
|
|
return gerror.Wrap(err, "更新回调失败状态失败")
|
|
}
|
|
|
|
_ = s.RecordOrderHistory(ctx, order.OrderNo, consts.CamelOilOrderChangeTypeCallbackFail, "", historyDesc)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// TriggerOrderCallback 触发订单回调
|
|
func (s *sCamelOil) TriggerOrderCallback(ctx context.Context, req *v1.OrderCallbackReq) (res *v1.OrderCallbackRes, err error) {
|
|
// 1. 查询订单信息
|
|
var order *entity.V1CamelOilOrder
|
|
err = dao.V1CamelOilOrder.Ctx(ctx).DB(config.GetDatabaseV1()).
|
|
Where(dao.V1CamelOilOrder.Columns().OrderNo, req.OrderNo).
|
|
Scan(&order)
|
|
|
|
if err != nil {
|
|
glog.Error(ctx, "查询订单信息失败", err)
|
|
return nil, err
|
|
}
|
|
|
|
if order == nil {
|
|
return nil, gerror.New("订单不存在")
|
|
}
|
|
|
|
// 2. 检查订单状态
|
|
if order.PayStatus != int(consts.CamelOilPaymentStatusPaid) {
|
|
return &v1.OrderCallbackRes{
|
|
Success: false,
|
|
Message: "订单未支付,无法回调",
|
|
}, nil
|
|
}
|
|
|
|
// 3. 执行回调
|
|
err = s.executeCallback(ctx, order)
|
|
// 4. 更新回调结果
|
|
success := err == nil
|
|
desc := "手动触发回调成功"
|
|
if err != nil {
|
|
desc = "回调失败" + err.Error()
|
|
}
|
|
_ = s.updateCallbackResult(ctx, order, success, desc)
|
|
|
|
return &v1.OrderCallbackRes{
|
|
Success: success,
|
|
Message: map[bool]string{true: "回调成功", false: "回调失败"}[success],
|
|
}, nil
|
|
}
|
|
|
|
// executeCallback 执行回调(内部方法)
|
|
func (s *sCamelOil) executeCallback(ctx context.Context, order *entity.V1CamelOilOrder) (err error) {
|
|
// 查询订单信息
|
|
var orderInfo *entity.V1OrderInfo
|
|
if err = dao.V1OrderInfo.Ctx(ctx).DB(config.GetDatabaseV1()).Where(dao.V1OrderInfo.Columns().BankOrderId, order.MerchantOrderId).Scan(&orderInfo); err != nil || orderInfo == nil || orderInfo.Id == 0 {
|
|
glog.Error(ctx, "查询订单失败", g.Map{"userOrderId": order.MerchantOrderId, "err": err})
|
|
return errors.New("订单不存在")
|
|
}
|
|
var merchantInfo *entity.V1MerchantInfo
|
|
if err = dao.V1MerchantInfo.Ctx(ctx).DB(config.GetDatabaseV1()).Where(dao.V1MerchantInfo.Columns().MerchantUid, orderInfo.MerchantUid).Scan(&merchantInfo); err != nil || merchantInfo == nil || merchantInfo.Id == 0 {
|
|
glog.Error(ctx, "查询商户信息失败", g.Map{"merchantId": orderInfo.MerchantUid, "err": err})
|
|
return errors.New("商户不存在")
|
|
}
|
|
// 发送 HTTP 回调请求
|
|
_, _ = gclient.New().Get(ctx, "http://kami_gateway:12309/myself/notify", g.Map{
|
|
"orderNo": order.OrderNo,
|
|
"orderPrice": order.Amount,
|
|
"factPrice": order.Amount,
|
|
"orderTime": order.CreatedAt,
|
|
"trxNo": order.OrderNo,
|
|
"payKey": merchantInfo.MerchantKey,
|
|
"statusCode": "1",
|
|
"failReason": "无",
|
|
})
|
|
return nil
|
|
}
|
|
|
|
// ProcessPendingCallbacks 处理待回调订单(定时任务使用)
|
|
func (s *sCamelOil) ProcessPendingCallbacks(ctx context.Context) error {
|
|
// 查询需要回调的订单(仅查询已绑定到 Token 的订单)
|
|
var orders []*entity.V1CamelOilOrder
|
|
err := dao.V1CamelOilOrder.Ctx(ctx).DB(config.GetDatabaseV1()).
|
|
InnerJoin(dao.V1CamelOilCardBinding.Table(), fmt.Sprintf("%s.%s = %s.%s",
|
|
dao.V1CamelOilOrder.Table(), dao.V1CamelOilOrder.Columns().Id,
|
|
dao.V1CamelOilCardBinding.Table(), dao.V1CamelOilCardBinding.Columns().OrderId)).
|
|
Where(dao.V1CamelOilOrder.Columns().PayStatus, consts.CamelOilPaymentStatusPaid).
|
|
Where(dao.V1CamelOilOrder.Columns().NotifyStatus, consts.CamelOilCallbackStatusPending).
|
|
WhereLTE(dao.V1CamelOilOrder.Columns().NotifyCount, 3).
|
|
Fields(dao.V1CamelOilOrder.Table() + ".*").
|
|
Distinct().
|
|
Limit(50).
|
|
Scan(&orders)
|
|
|
|
if err != nil {
|
|
glog.Error(ctx, "查询待回调订单失败", err)
|
|
return err
|
|
}
|
|
|
|
if len(orders) == 0 {
|
|
return nil
|
|
}
|
|
|
|
// 逐个处理回调
|
|
successCount := 0
|
|
for _, order := range orders {
|
|
err = s.executeCallback(ctx, order)
|
|
if err != nil {
|
|
// 回调失败
|
|
_ = s.updateCallbackResult(ctx, order, false, fmt.Sprintf("自动回调失败 %s", err.Error()))
|
|
glog.Error(ctx, "订单回调处理失败", err)
|
|
continue
|
|
}
|
|
// 回调成功
|
|
_ = s.updateCallbackResult(ctx, order, true, "自动回调成功")
|
|
successCount++
|
|
glog.Info(ctx, "订单回调处理完成", g.Map{
|
|
"total": len(orders),
|
|
"success": successCount,
|
|
"failed": len(orders) - successCount,
|
|
})
|
|
return nil
|
|
}
|
|
return nil
|
|
}
|