Files
kami_backend/internal/logic/camel_oil/order_callback.go
danial 3588bf9af6 feat(camel_oil): 支持Token管理与卡密绑定功能
- 新增CamelOilToken和CamelOilCardBinding数据库表,实现Token及卡密绑定记录管理
- 在service层增加Token的创建、查询、更新、删除及分页功能
- 实现卡密与Token绑定的业务逻辑,支持基于Token的卡密管理
- 在API层新增Token和卡密绑定相关接口:创建Token、获取Token详情、删除Token、列出Token及根据Token查询绑定卡密
- camel_oil_api新增绑卡接口,支持绑卡状态分类及错误处理
- 在定时任务中增加卡密绑定任务,实现自动处理已支付订单的卡密绑定
- 优化订单提交及支付流程,包含日志调整和请求参数随机扰动
- 统一调整camel_oil模块多控制器实现,完成账号状态查询及订单相关接口实现
- 注册更多camel_oil定时任务,包括订单支付检查、账号日重置和待回调订单处理任务
2025-11-23 00:08:35 +08:00

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
}