- 实现账号增删改查接口和逻辑 - 支持账号状态更新及状态历史记录功能 - 提供账号列表、历史和统计信息查询API - 实现账号轮询机制,支持按使用时间轮询获取账号 - 增加账号登录流程及批量登录功能,集成接码平台和平台API - 管理账号订单容量,支持容量检查与账号登录触发 - 提供账号池状态统计接口 - 账号历史记录查询支持多种变更类型文本展示 - 密码等敏感信息采用脱敏展示 - 完善日志记录和错误处理机制,保证业务稳定运行
165 lines
5.7 KiB
Go
165 lines
5.7 KiB
Go
package camel_oil
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"github.com/gogf/gf/v2/database/gdb"
|
||
"github.com/gogf/gf/v2/errors/gerror"
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
"github.com/gogf/gf/v2/os/gmlock"
|
||
"github.com/gogf/gf/v2/os/gtime"
|
||
"github.com/shopspring/decimal"
|
||
"kami/utility/integration/camel_oil_api"
|
||
"kami/utility/utils"
|
||
|
||
v1 "kami/api/camel_oil/v1"
|
||
"kami/internal/consts"
|
||
"kami/internal/dao"
|
||
"kami/internal/model/do"
|
||
"kami/internal/model/entity"
|
||
"kami/utility/config"
|
||
)
|
||
|
||
// ====================================================================================
|
||
// 订单管理相关方法
|
||
// ====================================================================================
|
||
|
||
// SubmitOrder 提交订单并返回支付宝支付链接
|
||
func (s *sCamelOil) SubmitOrder(ctx context.Context, req *v1.SubmitOrderReq) (res *v1.SubmitOrderRes, err error) {
|
||
// 1. 检查可用订单容量,低于50则触发账号登录任务
|
||
capacity, err := s.GetAvailableOrderCapacity(ctx)
|
||
if err != nil {
|
||
return nil, gerror.Wrap(err, "检查账号容量失败")
|
||
}
|
||
|
||
// 容量不足50,触发异步登录任务
|
||
if capacity <= 50 {
|
||
g.Log().Infof(ctx, "可用订单容量不足50(当前:%d),触发账号登录任务", capacity)
|
||
go func() {
|
||
if err = s.CheckAndTriggerAccountLogin(context.Background()); err != nil {
|
||
g.Log().Errorf(ctx, "触发账号登录任务失败:%v", err)
|
||
}
|
||
}()
|
||
}
|
||
|
||
accountCount, _ := s.GetOrderCountByStatus(ctx, consts.CamelOilAccountStatusOnline)
|
||
for i := 0; i < accountCount; i++ {
|
||
account, err := s.GetAvailableAccount(ctx)
|
||
if err != nil {
|
||
return nil, gerror.Wrap(err, "获取可用账号失败")
|
||
}
|
||
if account == nil {
|
||
return nil, gerror.New("暂无可用账号,请稍后重试")
|
||
}
|
||
platformOrderId, payId, err := camel_oil_api.NewClient().CreateOrder(ctx, account.Phone, account.Token, req.Amount)
|
||
if err != nil {
|
||
if err.Error() == "auth_error" {
|
||
_ = s.UpdateAccountStatus(ctx, account.Id, consts.CamelOilAccountStatusInvalid, consts.CamelOilAccountChangeTypeInvalidate, "账号token失效")
|
||
continue
|
||
}
|
||
return nil, err
|
||
}
|
||
// 生成系统订单号
|
||
orderNo := fmt.Sprintf("CO%s", utils.GenerateRandomUUID())
|
||
|
||
gmlock.LockFunc(fmt.Sprintf("camelSubmitOrder_%d", account.Id), func() {
|
||
// 4. 保存订单记录并更新账号使用信息(使用事务)
|
||
err = dao.V1CamelOilOrder.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||
// 插入订单
|
||
_, err = dao.V1CamelOilOrder.Ctx(ctx).DB(config.GetDatabaseV1()).Insert(&do.V1CamelOilOrder{
|
||
OrderNo: orderNo,
|
||
MerchantOrderId: req.MerchantOrderId,
|
||
AccountId: account.Id,
|
||
AccountName: account.AccountName,
|
||
PlatformOrderNo: platformOrderId,
|
||
Amount: decimal.NewFromFloat(req.Amount),
|
||
AlipayUrl: payId,
|
||
Status: 1, // 1=待支付
|
||
PayStatus: 0, // 0=未支付
|
||
NotifyStatus: 0, // 0=未回调
|
||
NotifyCount: 0,
|
||
Attach: req.Attach,
|
||
})
|
||
if err != nil {
|
||
return gerror.Wrap(err, "保存订单记录失败")
|
||
}
|
||
|
||
_, err = dao.V1CamelOilAccount.Ctx(ctx).DB(config.GetDatabaseV1()).
|
||
Where(dao.V1CamelOilAccount.Columns().Id, account.Id).
|
||
Increment(dao.V1CamelOilAccount.Columns().DailyOrderCount, 1)
|
||
if err != nil {
|
||
return gerror.Wrap(err, "更新账号使用记录失败")
|
||
}
|
||
|
||
_, err = dao.V1CamelOilAccount.Ctx(ctx).DB(config.GetDatabaseV1()).
|
||
Where(dao.V1CamelOilAccount.Columns().Id, account.Id).
|
||
Increment(dao.V1CamelOilAccount.Columns().TotalOrderCount, 1)
|
||
if err != nil {
|
||
return gerror.Wrap(err, "更新账号使用记录失败")
|
||
}
|
||
|
||
// 检查账号是否达到单日限额(10单)
|
||
var updatedAccount *entity.V1CamelOilAccount
|
||
err = dao.V1CamelOilAccount.Ctx(ctx).DB(config.GetDatabaseV1()).
|
||
Where(dao.V1CamelOilAccount.Columns().Id, account.Id).
|
||
Scan(&updatedAccount)
|
||
if err != nil {
|
||
return gerror.Wrap(err, "查询账号失败")
|
||
}
|
||
|
||
if updatedAccount.DailyOrderCount >= 10 {
|
||
// 达到限额,标记为已暂停 (status=3)
|
||
_, err = dao.V1CamelOilAccount.Ctx(ctx).DB(config.GetDatabaseV1()).
|
||
Where(dao.V1CamelOilAccount.Columns().Id, account.Id).
|
||
Update(do.V1CamelOilAccount{
|
||
Status: consts.CamelOilAccountStatusPaused, // 3=暂停
|
||
})
|
||
if err != nil {
|
||
return gerror.Wrap(err, "更新账号状态失败")
|
||
}
|
||
|
||
g.Log().Infof(ctx, "账号[%s]达到单日限额10单,已暂停", account.Phone)
|
||
}
|
||
|
||
// 记录订单历史
|
||
_, err = dao.V1CamelOilOrderHistory.Ctx(ctx).DB(config.GetDatabaseV1()).Data(&do.V1CamelOilOrderHistory{
|
||
HistoryUuid: utils.GenerateRandomUUID(),
|
||
OrderNo: orderNo,
|
||
ChangeType: "create",
|
||
AccountId: account.Id,
|
||
AccountName: account.AccountName,
|
||
Remark: fmt.Sprintf("创建订单:商户订单号=%s,平台订单号=%s", req.MerchantOrderId, platformOrderId),
|
||
}).Insert()
|
||
if err != nil {
|
||
g.Log().Errorf(ctx, "记录订单历史失败:%v", err)
|
||
}
|
||
|
||
// 记录账号历史
|
||
_ = s.RecordAccountHistory(ctx, account.Id, consts.CamelOilAccountChangeTypeOrderBind,
|
||
consts.CamelOilAccountStatus(account.Status), consts.CamelOilAccountStatus(account.Status),
|
||
fmt.Sprintf("绑定订单:%s", orderNo))
|
||
|
||
return nil
|
||
})
|
||
})
|
||
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 5. 返回支付链接
|
||
res = &v1.SubmitOrderRes{
|
||
OrderNo: orderNo,
|
||
AlipayUrl: "",
|
||
Amount: req.Amount,
|
||
CreatedAt: gtime.Now(),
|
||
}
|
||
|
||
g.Log().Infof(ctx, "订单创建成功:商户订单号=%s,平台订单号=%s,账号=%s 系统订单号=%s",
|
||
req.MerchantOrderId, platformOrderId, account.Phone, orderNo)
|
||
|
||
return res, nil
|
||
}
|
||
return nil, gerror.New("暂无可用账号,请稍后重试")
|
||
}
|