first commit
This commit is contained in:
641
app/main/api/internal/service/agentService.go
Normal file
641
app/main/api/internal/service/agentService.go
Normal file
@@ -0,0 +1,641 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"strconv"
|
||||
"time"
|
||||
"ycc-server/app/main/api/internal/config"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/pkg/lzkit/lzUtils"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
// AgentService 新代理系统服务
|
||||
type AgentService struct {
|
||||
config config.Config
|
||||
OrderModel model.OrderModel
|
||||
AgentModel model.AgentModel
|
||||
AgentWalletModel model.AgentWalletModel
|
||||
AgentRelationModel model.AgentRelationModel
|
||||
AgentLinkModel model.AgentLinkModel
|
||||
AgentOrderModel model.AgentOrderModel
|
||||
AgentCommissionModel model.AgentCommissionModel
|
||||
AgentRebateModel model.AgentRebateModel
|
||||
AgentUpgradeModel model.AgentUpgradeModel
|
||||
AgentWithdrawalModel model.AgentWithdrawalModel
|
||||
AgentConfigModel model.AgentConfigModel
|
||||
AgentProductConfigModel model.AgentProductConfigModel
|
||||
AgentRealNameModel model.AgentRealNameModel
|
||||
AgentWithdrawalTaxModel model.AgentWithdrawalTaxModel
|
||||
}
|
||||
|
||||
// NewAgentService 创建新的代理服务
|
||||
func NewAgentService(
|
||||
c config.Config,
|
||||
orderModel model.OrderModel,
|
||||
agentModel model.AgentModel,
|
||||
agentWalletModel model.AgentWalletModel,
|
||||
agentRelationModel model.AgentRelationModel,
|
||||
agentLinkModel model.AgentLinkModel,
|
||||
agentOrderModel model.AgentOrderModel,
|
||||
agentCommissionModel model.AgentCommissionModel,
|
||||
agentRebateModel model.AgentRebateModel,
|
||||
agentUpgradeModel model.AgentUpgradeModel,
|
||||
agentWithdrawalModel model.AgentWithdrawalModel,
|
||||
agentConfigModel model.AgentConfigModel,
|
||||
agentProductConfigModel model.AgentProductConfigModel,
|
||||
agentRealNameModel model.AgentRealNameModel,
|
||||
agentWithdrawalTaxModel model.AgentWithdrawalTaxModel,
|
||||
) *AgentService {
|
||||
return &AgentService{
|
||||
config: c,
|
||||
OrderModel: orderModel,
|
||||
AgentModel: agentModel,
|
||||
AgentWalletModel: agentWalletModel,
|
||||
AgentRelationModel: agentRelationModel,
|
||||
AgentLinkModel: agentLinkModel,
|
||||
AgentOrderModel: agentOrderModel,
|
||||
AgentCommissionModel: agentCommissionModel,
|
||||
AgentRebateModel: agentRebateModel,
|
||||
AgentUpgradeModel: agentUpgradeModel,
|
||||
AgentWithdrawalModel: agentWithdrawalModel,
|
||||
AgentConfigModel: agentConfigModel,
|
||||
AgentProductConfigModel: agentProductConfigModel,
|
||||
AgentRealNameModel: agentRealNameModel,
|
||||
AgentWithdrawalTaxModel: agentWithdrawalTaxModel,
|
||||
}
|
||||
}
|
||||
|
||||
// AgentProcess 处理代理订单(新系统)
|
||||
// 根据新代理系统的收益分配规则处理订单
|
||||
func (s *AgentService) AgentProcess(ctx context.Context, order *model.Order) error {
|
||||
// 1. 检查是否是代理推广订单
|
||||
agentOrder, err := s.AgentOrderModel.FindOneByOrderId(ctx, order.Id)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
// 不是代理订单,直接返回
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(err, "查询代理订单失败, orderId: %d", order.Id)
|
||||
}
|
||||
|
||||
// 2. 检查订单是否已处理
|
||||
if agentOrder.ProcessStatus == 1 {
|
||||
logx.Infof("订单已处理, orderId: %d", order.Id)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 3. 获取代理信息
|
||||
agent, err := s.AgentModel.FindOne(ctx, agentOrder.AgentId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查询代理信息失败, agentId: %d", agentOrder.AgentId)
|
||||
}
|
||||
|
||||
// 4. 获取系统配置
|
||||
basePrice, err := s.getConfigFloat(ctx, "base_price")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "获取基础底价配置失败")
|
||||
}
|
||||
|
||||
// 6. 使用事务处理订单
|
||||
return s.AgentWalletModel.Trans(ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||
// 6.1 计算实际底价和代理收益
|
||||
levelBonus := s.getLevelBonus(agent.Level)
|
||||
actualBasePrice := basePrice + float64(levelBonus)
|
||||
|
||||
// 6.2 计算提价成本
|
||||
priceThreshold, _ := s.getConfigFloat(ctx, "price_threshold")
|
||||
priceFeeRate, _ := s.getConfigFloat(ctx, "price_fee_rate")
|
||||
priceCost := s.calculatePriceCost(agentOrder.SetPrice, priceThreshold, priceFeeRate)
|
||||
|
||||
// 6.3 计算代理收益
|
||||
agentProfit := agentOrder.SetPrice - actualBasePrice - priceCost
|
||||
|
||||
// 6.4 更新代理订单记录
|
||||
agentOrder.ProcessStatus = 1
|
||||
agentOrder.ProcessTime = lzUtils.TimeToNullTime(time.Now())
|
||||
agentOrder.ProcessRemark = lzUtils.StringToNullString("处理成功")
|
||||
if err := s.AgentOrderModel.UpdateWithVersion(transCtx, session, agentOrder); err != nil {
|
||||
return errors.Wrapf(err, "更新代理订单失败")
|
||||
}
|
||||
|
||||
// 6.5 发放代理佣金
|
||||
if err := s.giveAgentCommission(transCtx, session, agentOrder.AgentId, order.Id, order.ProductId, agentProfit); err != nil {
|
||||
return errors.Wrapf(err, "发放代理佣金失败")
|
||||
}
|
||||
|
||||
// 6.6 分配等级加成返佣给上级链
|
||||
if levelBonus > 0 {
|
||||
if err := s.distributeLevelBonus(transCtx, session, agent, order.Id, order.ProductId, float64(levelBonus), levelBonus); err != nil {
|
||||
return errors.Wrapf(err, "分配等级加成返佣失败")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// getLevelBonus 获取等级加成
|
||||
func (s *AgentService) getLevelBonus(level int64) int64 {
|
||||
switch level {
|
||||
case 1: // 普通
|
||||
return 6
|
||||
case 2: // 黄金
|
||||
return 3
|
||||
case 3: // 钻石
|
||||
return 0
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// calculatePriceCost 计算提价成本
|
||||
func (s *AgentService) calculatePriceCost(setPrice, priceThreshold, priceFeeRate float64) float64 {
|
||||
if setPrice <= priceThreshold {
|
||||
return 0
|
||||
}
|
||||
return (setPrice - priceThreshold) * priceFeeRate
|
||||
}
|
||||
|
||||
// giveAgentCommission 发放代理佣金
|
||||
func (s *AgentService) giveAgentCommission(ctx context.Context, session sqlx.Session, agentId, orderId, productId int64, amount float64) error {
|
||||
// 1. 创建佣金记录
|
||||
commission := &model.AgentCommission{
|
||||
AgentId: agentId,
|
||||
OrderId: orderId,
|
||||
ProductId: productId,
|
||||
Amount: amount,
|
||||
Status: 1, // 已发放
|
||||
}
|
||||
if _, err := s.AgentCommissionModel.Insert(ctx, session, commission); err != nil {
|
||||
return errors.Wrapf(err, "创建佣金记录失败")
|
||||
}
|
||||
|
||||
// 2. 更新钱包余额
|
||||
wallet, err := s.AgentWalletModel.FindOneByAgentId(ctx, agentId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查询钱包失败, agentId: %d", agentId)
|
||||
}
|
||||
|
||||
wallet.Balance += amount
|
||||
wallet.TotalEarnings += amount
|
||||
if err := s.AgentWalletModel.UpdateWithVersion(ctx, session, wallet); err != nil {
|
||||
return errors.Wrapf(err, "更新钱包失败")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// distributeLevelBonus 分配等级加成返佣给上级链
|
||||
func (s *AgentService) distributeLevelBonus(ctx context.Context, session sqlx.Session, agent *model.Agent, orderId, productId int64, levelBonus float64, levelBonusInt int64) error {
|
||||
// 钻石代理:等级加成为0,无返佣分配
|
||||
if agent.Level == 3 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 黄金代理:等级加成3元,全部给钻石上级
|
||||
if agent.Level == 2 {
|
||||
diamondParent, err := s.findDiamondParent(ctx, agent.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查找钻石上级失败")
|
||||
}
|
||||
if diamondParent != nil {
|
||||
return s.giveRebate(ctx, session, diamondParent.Id, agent.Id, orderId, productId, levelBonus, levelBonusInt, 2) // 2=钻石上级返佣
|
||||
}
|
||||
// 找不到钻石上级,返佣归平台(异常情况)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 普通代理:等级加成6元,按规则分配给上级链
|
||||
if agent.Level == 1 {
|
||||
return s.distributeNormalAgentBonus(ctx, session, agent, orderId, productId, levelBonus, levelBonusInt)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// distributeNormalAgentBonus 普通代理的等级加成返佣分配(6元)
|
||||
func (s *AgentService) distributeNormalAgentBonus(ctx context.Context, session sqlx.Session, agent *model.Agent, orderId, productId int64, amount float64, levelBonusInt int64) error {
|
||||
// 1. 查找直接上级
|
||||
parent, err := s.findDirectParent(ctx, agent.Id)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return errors.Wrapf(err, "查找直接上级失败")
|
||||
}
|
||||
|
||||
if parent == nil {
|
||||
// 无上级,全部归平台
|
||||
return nil
|
||||
}
|
||||
|
||||
// 2. 给直接上级分配固定金额
|
||||
var directParentAmount float64
|
||||
switch parent.Level {
|
||||
case 3: // 钻石
|
||||
directParentAmount = 6
|
||||
case 2: // 黄金
|
||||
directParentAmount = 3
|
||||
case 1: // 普通
|
||||
directParentAmount = 2
|
||||
default:
|
||||
directParentAmount = 0
|
||||
}
|
||||
|
||||
if directParentAmount > 0 {
|
||||
if err := s.giveRebate(ctx, session, parent.Id, agent.Id, orderId, productId, directParentAmount, levelBonusInt, 1); err != nil {
|
||||
return errors.Wrapf(err, "给直接上级返佣失败")
|
||||
}
|
||||
}
|
||||
|
||||
remaining := amount - directParentAmount
|
||||
if remaining <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 3. 分配剩余金额
|
||||
// 确定查找起点:直接上级是普通时从直接上级开始查找,否则从直接上级的上级开始查找
|
||||
searchStart := parent
|
||||
if parent.Level != 1 {
|
||||
searchStartParent, err := s.findDirectParent(ctx, parent.Id)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return errors.Wrapf(err, "查找上级的上级失败")
|
||||
}
|
||||
if searchStartParent != nil {
|
||||
searchStart = searchStartParent
|
||||
}
|
||||
}
|
||||
|
||||
if searchStart != nil {
|
||||
// 查找上级链中的钻石和黄金
|
||||
diamondParent, _ := s.findDiamondParent(ctx, searchStart.Id)
|
||||
goldParent, _ := s.findGoldParent(ctx, searchStart.Id)
|
||||
|
||||
// 按优先级分配剩余金额
|
||||
if diamondParent != nil {
|
||||
// 优先级1:有钻石,剩余金额全部给钻石
|
||||
return s.giveRebate(ctx, session, diamondParent.Id, agent.Id, orderId, productId, remaining, levelBonusInt, 2)
|
||||
} else if goldParent != nil {
|
||||
// 优先级2:只有黄金,最多3元给黄金,剩余归平台
|
||||
goldAmount := remaining
|
||||
if goldAmount > 3 {
|
||||
goldAmount = 3
|
||||
}
|
||||
if err := s.giveRebate(ctx, session, goldParent.Id, agent.Id, orderId, productId, goldAmount, levelBonusInt, 3); err != nil {
|
||||
return errors.Wrapf(err, "给黄金上级返佣失败")
|
||||
}
|
||||
// 剩余归平台(不需要记录)
|
||||
}
|
||||
// 优先级3:都没有,剩余金额归平台(不需要记录)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// giveRebate 发放返佣
|
||||
func (s *AgentService) giveRebate(ctx context.Context, session sqlx.Session, agentId, sourceAgentId, orderId, productId int64, amount float64, levelBonus int64, rebateType int64) error {
|
||||
// 1. 创建返佣记录
|
||||
rebate := &model.AgentRebate{
|
||||
AgentId: agentId,
|
||||
SourceAgentId: sourceAgentId,
|
||||
OrderId: orderId,
|
||||
ProductId: productId,
|
||||
RebateType: rebateType,
|
||||
LevelBonus: float64(levelBonus), // 等级加成金额
|
||||
RebateAmount: amount,
|
||||
Status: 1, // 已发放
|
||||
}
|
||||
if _, err := s.AgentRebateModel.Insert(ctx, session, rebate); err != nil {
|
||||
return errors.Wrapf(err, "创建返佣记录失败")
|
||||
}
|
||||
|
||||
// 2. 更新钱包余额
|
||||
wallet, err := s.AgentWalletModel.FindOneByAgentId(ctx, agentId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查询钱包失败, agentId: %d", agentId)
|
||||
}
|
||||
|
||||
wallet.Balance += amount
|
||||
wallet.TotalEarnings += amount
|
||||
if err := s.AgentWalletModel.UpdateWithVersion(ctx, session, wallet); err != nil {
|
||||
return errors.Wrapf(err, "更新钱包失败")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindDirectParent 查找直接上级(公开方法)
|
||||
func (s *AgentService) FindDirectParent(ctx context.Context, agentId int64) (*model.Agent, error) {
|
||||
return s.findDirectParent(ctx, agentId)
|
||||
}
|
||||
|
||||
// findDirectParent 查找直接上级
|
||||
func (s *AgentService) findDirectParent(ctx context.Context, agentId int64) (*model.Agent, error) {
|
||||
// 查找关系类型为1(直接关系)的上级
|
||||
builder := s.AgentRelationModel.SelectBuilder()
|
||||
builder = builder.Where("child_id = ? AND relation_type = ? AND del_state = ?", agentId, 1, globalkey.DelStateNo)
|
||||
relations, err := s.AgentRelationModel.FindAll(ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(relations) == 0 {
|
||||
return nil, model.ErrNotFound
|
||||
}
|
||||
|
||||
// 返回第一个直接上级
|
||||
return s.AgentModel.FindOne(ctx, relations[0].ParentId)
|
||||
}
|
||||
|
||||
// findDiamondParent 向上查找钻石上级
|
||||
func (s *AgentService) findDiamondParent(ctx context.Context, agentId int64) (*model.Agent, error) {
|
||||
currentId := agentId
|
||||
maxDepth := 100 // 防止无限循环
|
||||
depth := 0
|
||||
|
||||
for depth < maxDepth {
|
||||
parent, err := s.findDirectParent(ctx, currentId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, model.ErrNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if parent.Level == 3 { // 钻石
|
||||
return parent, nil
|
||||
}
|
||||
|
||||
currentId = parent.Id
|
||||
depth++
|
||||
}
|
||||
|
||||
return nil, model.ErrNotFound
|
||||
}
|
||||
|
||||
// findGoldParent 向上查找黄金上级
|
||||
func (s *AgentService) findGoldParent(ctx context.Context, agentId int64) (*model.Agent, error) {
|
||||
currentId := agentId
|
||||
maxDepth := 100 // 防止无限循环
|
||||
depth := 0
|
||||
|
||||
for depth < maxDepth {
|
||||
parent, err := s.findDirectParent(ctx, currentId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, model.ErrNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if parent.Level == 2 { // 黄金
|
||||
return parent, nil
|
||||
}
|
||||
|
||||
currentId = parent.Id
|
||||
depth++
|
||||
}
|
||||
|
||||
return nil, model.ErrNotFound
|
||||
}
|
||||
|
||||
// getConfigFloat 获取配置值(浮点数)
|
||||
func (s *AgentService) getConfigFloat(ctx context.Context, configKey string) (float64, error) {
|
||||
config, err := s.AgentConfigModel.FindOneByConfigKey(ctx, configKey)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
value, err := strconv.ParseFloat(config.ConfigValue, 64)
|
||||
if err != nil {
|
||||
return 0, errors.Wrapf(err, "解析配置值失败, key: %s, value: %s", configKey, config.ConfigValue)
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// getConfigInt 获取配置值(整数)
|
||||
func (s *AgentService) getConfigInt(ctx context.Context, configKey string) (int64, error) {
|
||||
config, err := s.AgentConfigModel.FindOneByConfigKey(ctx, configKey)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
value, err := strconv.ParseInt(config.ConfigValue, 10, 64)
|
||||
if err != nil {
|
||||
return 0, errors.Wrapf(err, "解析配置值失败, key: %s, value: %s", configKey, config.ConfigValue)
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// ProcessUpgrade 处理代理升级
|
||||
func (s *AgentService) ProcessUpgrade(ctx context.Context, agentId, toLevel int64, upgradeType int64, upgradeFee, rebateAmount float64, orderNo string, operatorAgentId int64) error {
|
||||
return s.AgentWalletModel.Trans(ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||
// 1. 获取代理信息
|
||||
agent, err := s.AgentModel.FindOne(transCtx, agentId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查询代理信息失败, agentId: %d", agentId)
|
||||
}
|
||||
|
||||
// 2. 如果是自主付费升级,处理返佣
|
||||
if upgradeType == 1 { // 自主付费
|
||||
// 查找原直接上级
|
||||
parent, err := s.findDirectParent(transCtx, agentId)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return errors.Wrapf(err, "查找直接上级失败")
|
||||
}
|
||||
|
||||
if parent != nil && rebateAmount > 0 {
|
||||
// 返佣给原直接上级
|
||||
if err := s.giveRebateForUpgrade(transCtx, session, parent.Id, agentId, rebateAmount); err != nil {
|
||||
return errors.Wrapf(err, "返佣给上级失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 执行升级操作
|
||||
agent.Level = toLevel
|
||||
|
||||
// 4. 检查是否需要脱离直接上级关系
|
||||
needDetach, err := s.needDetachFromParent(transCtx, agent, toLevel)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "检查是否需要脱离关系失败")
|
||||
}
|
||||
|
||||
if needDetach {
|
||||
// 脱离直接上级关系
|
||||
if err := s.detachFromParent(transCtx, session, agentId); err != nil {
|
||||
return errors.Wrapf(err, "脱离直接上级关系失败")
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 如果升级为钻石,独立成新团队
|
||||
if toLevel == 3 {
|
||||
agent.TeamLeaderId = sql.NullInt64{Int64: agentId, Valid: true}
|
||||
// 更新所有下级的团队首领
|
||||
if err := s.updateChildrenTeamLeader(transCtx, session, agentId, agentId); err != nil {
|
||||
return errors.Wrapf(err, "更新下级团队首领失败")
|
||||
}
|
||||
} else {
|
||||
// 更新团队首领(查找上级链中的钻石代理)
|
||||
teamLeaderId, err := s.findTeamLeaderId(transCtx, agentId)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return errors.Wrapf(err, "查找团队首领失败")
|
||||
}
|
||||
if teamLeaderId > 0 {
|
||||
agent.TeamLeaderId = sql.NullInt64{Int64: teamLeaderId, Valid: true}
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 更新代理记录
|
||||
if err := s.AgentModel.UpdateWithVersion(transCtx, session, agent); err != nil {
|
||||
return errors.Wrapf(err, "更新代理记录失败")
|
||||
}
|
||||
|
||||
// 7. 更新升级记录状态
|
||||
// 这里需要先查询升级记录,暂时先跳过,在logic中处理
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// needDetachFromParent 检查是否需要脱离直接上级关系
|
||||
func (s *AgentService) needDetachFromParent(ctx context.Context, agent *model.Agent, newLevel int64) (bool, error) {
|
||||
parent, err := s.findDirectParent(ctx, agent.Id)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return false, nil // 没有上级,不需要脱离
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 规则1:下级不能比上级等级高
|
||||
if newLevel > parent.Level {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// 规则2:同级不能作为上下级(除了普通代理)
|
||||
if newLevel == parent.Level {
|
||||
if newLevel == 2 || newLevel == 3 { // 黄金或钻石
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 规则3:钻石 → 黄金禁止(特殊规则)
|
||||
if newLevel == 2 && parent.Level == 3 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// detachFromParent 脱离直接上级关系
|
||||
func (s *AgentService) detachFromParent(ctx context.Context, session sqlx.Session, agentId int64) error {
|
||||
// 查找直接关系
|
||||
builder := s.AgentRelationModel.SelectBuilder().
|
||||
Where("child_id = ? AND relation_type = ? AND del_state = ?", agentId, 1, globalkey.DelStateNo)
|
||||
relations, err := s.AgentRelationModel.FindAll(ctx, builder, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(relations) == 0 {
|
||||
return nil // 没有关系,不需要脱离
|
||||
}
|
||||
|
||||
// 将直接关系标记为已脱离
|
||||
relation := relations[0]
|
||||
relation.RelationType = 2 // 已脱离
|
||||
relation.DetachReason = lzUtils.StringToNullString("upgrade")
|
||||
relation.DetachTime = lzUtils.TimeToNullTime(time.Now())
|
||||
|
||||
if err := s.AgentRelationModel.UpdateWithVersion(ctx, session, relation); err != nil {
|
||||
return errors.Wrapf(err, "更新关系记录失败")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateChildrenTeamLeader 更新所有下级的团队首领
|
||||
func (s *AgentService) updateChildrenTeamLeader(ctx context.Context, session sqlx.Session, agentId, teamLeaderId int64) error {
|
||||
// 递归更新所有下级
|
||||
var updateChildren func(int64) error
|
||||
updateChildren = func(parentId int64) error {
|
||||
// 查找直接下级
|
||||
builder := s.AgentRelationModel.SelectBuilder().
|
||||
Where("parent_id = ? AND relation_type = ? AND del_state = ?", parentId, 1, globalkey.DelStateNo)
|
||||
relations, err := s.AgentRelationModel.FindAll(ctx, builder, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, relation := range relations {
|
||||
child, err := s.AgentModel.FindOne(ctx, relation.ChildId)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
child.TeamLeaderId = sql.NullInt64{Int64: teamLeaderId, Valid: true}
|
||||
if err := s.AgentModel.UpdateWithVersion(ctx, session, child); err != nil {
|
||||
return errors.Wrapf(err, "更新下级团队首领失败, childId: %d", child.Id)
|
||||
}
|
||||
|
||||
// 递归更新下级的下级
|
||||
if err := updateChildren(child.Id); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return updateChildren(agentId)
|
||||
}
|
||||
|
||||
// findTeamLeaderId 查找团队首领ID(钻石代理)
|
||||
func (s *AgentService) findTeamLeaderId(ctx context.Context, agentId int64) (int64, error) {
|
||||
diamondParent, err := s.findDiamondParent(ctx, agentId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return 0, nil
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
return diamondParent.Id, nil
|
||||
}
|
||||
|
||||
// giveRebateForUpgrade 发放升级返佣
|
||||
func (s *AgentService) giveRebateForUpgrade(ctx context.Context, session sqlx.Session, parentAgentId, upgradeAgentId int64, amount float64) error {
|
||||
// 更新钱包余额
|
||||
wallet, err := s.AgentWalletModel.FindOneByAgentId(ctx, parentAgentId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查询钱包失败, agentId: %d", parentAgentId)
|
||||
}
|
||||
|
||||
wallet.Balance += amount
|
||||
wallet.TotalEarnings += amount
|
||||
if err := s.AgentWalletModel.UpdateWithVersion(ctx, session, wallet); err != nil {
|
||||
return errors.Wrapf(err, "更新钱包失败")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUpgradeFee 获取升级费用
|
||||
func (s *AgentService) GetUpgradeFee(fromLevel, toLevel int64) float64 {
|
||||
if fromLevel == 1 && toLevel == 2 {
|
||||
return 199 // 普通→黄金
|
||||
} else if toLevel == 3 {
|
||||
return 980 // 升级为钻石
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetUpgradeRebate 获取升级返佣金额
|
||||
func (s *AgentService) GetUpgradeRebate(fromLevel, toLevel int64) float64 {
|
||||
if fromLevel == 1 && toLevel == 2 {
|
||||
return 139 // 普通→黄金返佣
|
||||
} else if toLevel == 3 {
|
||||
return 680 // 升级为钻石返佣
|
||||
}
|
||||
return 0
|
||||
}
|
||||
Reference in New Issue
Block a user