v1.1
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/pkg/lzkit/lzUtils"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
@@ -205,20 +206,21 @@ func (s *AgentService) calculatePriceCost(setPrice, priceThreshold, priceFeeRate
|
||||
// giveAgentCommission 发放代理佣金
|
||||
// orderPrice: 订单单价,用于判断是否需要冻结
|
||||
// 返回:freezeTaskId(如果有冻结任务),error
|
||||
func (s *AgentService) giveAgentCommission(ctx context.Context, session sqlx.Session, agentId, orderId, productId int64, amount float64, orderPrice float64) (int64, error) {
|
||||
func (s *AgentService) giveAgentCommission(ctx context.Context, session sqlx.Session, agentId, orderId, productId string, amount float64, orderPrice float64) (string, error) {
|
||||
// 1. 创建佣金记录
|
||||
commission := &model.AgentCommission{
|
||||
Id: uuid.NewString(),
|
||||
AgentId: agentId,
|
||||
OrderId: orderId,
|
||||
ProductId: productId,
|
||||
Amount: amount,
|
||||
Status: 1, // 已发放
|
||||
}
|
||||
commissionResult, err := s.AgentCommissionModel.Insert(ctx, session, commission)
|
||||
_, err := s.AgentCommissionModel.Insert(ctx, session, commission)
|
||||
if err != nil {
|
||||
return 0, errors.Wrapf(err, "创建佣金记录失败")
|
||||
return "", errors.Wrapf(err, "创建佣金记录失败")
|
||||
}
|
||||
commissionId, _ := commissionResult.LastInsertId()
|
||||
commissionId := commission.Id
|
||||
|
||||
// 2. 判断是否需要冻结
|
||||
// 2.1 获取冻结阈值配置(默认100元)
|
||||
@@ -231,7 +233,7 @@ func (s *AgentService) giveAgentCommission(ctx context.Context, session sqlx.Ses
|
||||
|
||||
// 2.2 判断订单单价是否达到冻结阈值
|
||||
freezeAmount := 0.0
|
||||
var freezeTaskId int64 = 0
|
||||
var freezeTaskId string = ""
|
||||
if orderPrice >= freezeThreshold {
|
||||
// 2.3 获取冻结比例配置(默认10%)
|
||||
freezeRatio, err := s.getConfigFloat(ctx, "commission_freeze_ratio")
|
||||
@@ -266,6 +268,7 @@ func (s *AgentService) giveAgentCommission(ctx context.Context, session sqlx.Ses
|
||||
|
||||
// 创建冻结任务记录
|
||||
freezeTask := &model.AgentFreezeTask{
|
||||
Id: uuid.NewString(),
|
||||
AgentId: agentId,
|
||||
OrderId: orderId,
|
||||
CommissionId: commissionId,
|
||||
@@ -277,18 +280,18 @@ func (s *AgentService) giveAgentCommission(ctx context.Context, session sqlx.Ses
|
||||
UnfreezeTime: unfreezeTime,
|
||||
Remark: lzUtils.StringToNullString(fmt.Sprintf("订单单价%.2f元,冻结比例%.2f%%,解冻天数%d天", orderPrice, freezeRatio*100, unfreezeDays)),
|
||||
}
|
||||
freezeTaskResult, err := s.AgentFreezeTaskModel.Insert(ctx, session, freezeTask)
|
||||
_, err = s.AgentFreezeTaskModel.Insert(ctx, session, freezeTask)
|
||||
if err != nil {
|
||||
return 0, errors.Wrapf(err, "创建冻结任务失败")
|
||||
return "", errors.Wrapf(err, "创建冻结任务失败")
|
||||
}
|
||||
freezeTaskId, _ = freezeTaskResult.LastInsertId()
|
||||
freezeTaskId = freezeTask.Id
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 更新钱包余额
|
||||
wallet, err := s.AgentWalletModel.FindOneByAgentId(ctx, agentId)
|
||||
if err != nil {
|
||||
return 0, errors.Wrapf(err, "查询钱包失败, agentId: %d", agentId)
|
||||
return "", errors.Wrapf(err, "查询钱包失败, agentId: %s", agentId)
|
||||
}
|
||||
|
||||
// 实际到账金额 = 佣金金额 - 冻结金额
|
||||
@@ -298,14 +301,14 @@ func (s *AgentService) giveAgentCommission(ctx context.Context, session sqlx.Ses
|
||||
wallet.FrozenBalance += freezeAmount
|
||||
wallet.TotalEarnings += amount // 累计收益包含冻结部分
|
||||
if err := s.AgentWalletModel.UpdateWithVersion(ctx, session, wallet); err != nil {
|
||||
return 0, errors.Wrapf(err, "更新钱包失败")
|
||||
return "", errors.Wrapf(err, "更新钱包失败")
|
||||
}
|
||||
|
||||
return freezeTaskId, nil
|
||||
}
|
||||
|
||||
// distributeLevelBonus 分配等级加成返佣给上级链
|
||||
func (s *AgentService) distributeLevelBonus(ctx context.Context, session sqlx.Session, agent *model.Agent, orderId, productId int64, levelBonus float64, levelBonusInt int64) error {
|
||||
func (s *AgentService) distributeLevelBonus(ctx context.Context, session sqlx.Session, agent *model.Agent, orderId, productId string, levelBonus float64, levelBonusInt int64) error {
|
||||
// 钻石代理:等级加成为0,无返佣分配
|
||||
if agent.Level == 3 {
|
||||
return nil
|
||||
@@ -377,7 +380,7 @@ func (s *AgentService) distributeLevelBonus(ctx context.Context, session sqlx.Se
|
||||
// 注意:findDiamondParent 和 findGoldParent 会自动跳过中间的所有普通代理,
|
||||
//
|
||||
// 直接向上查找到第一个钻石或黄金代理
|
||||
func (s *AgentService) distributeNormalAgentBonus(ctx context.Context, session sqlx.Session, agent *model.Agent, orderId, productId int64, amount float64, levelBonusInt int64) error {
|
||||
func (s *AgentService) distributeNormalAgentBonus(ctx context.Context, session sqlx.Session, agent *model.Agent, orderId, productId string, amount float64, levelBonusInt int64) error {
|
||||
// 1. 查找直接上级
|
||||
parent, err := s.findDirectParent(ctx, agent.Id)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
@@ -626,18 +629,19 @@ func (s *AgentService) getRebateConfigFloat(ctx context.Context, configKey strin
|
||||
}
|
||||
|
||||
// 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, // 已发放
|
||||
}
|
||||
func (s *AgentService) giveRebate(ctx context.Context, session sqlx.Session, agentId, sourceAgentId, orderId, productId string, amount float64, levelBonus int64, rebateType int64) error {
|
||||
// 1. 创建返佣记录
|
||||
rebate := &model.AgentRebate{
|
||||
Id: uuid.NewString(),
|
||||
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, "创建返佣记录失败")
|
||||
}
|
||||
@@ -658,12 +662,12 @@ func (s *AgentService) giveRebate(ctx context.Context, session sqlx.Session, age
|
||||
}
|
||||
|
||||
// FindDirectParent 查找直接上级(公开方法)
|
||||
func (s *AgentService) FindDirectParent(ctx context.Context, agentId int64) (*model.Agent, error) {
|
||||
func (s *AgentService) FindDirectParent(ctx context.Context, agentId string) (*model.Agent, error) {
|
||||
return s.findDirectParent(ctx, agentId)
|
||||
}
|
||||
|
||||
// findDirectParent 查找直接上级
|
||||
func (s *AgentService) findDirectParent(ctx context.Context, agentId int64) (*model.Agent, error) {
|
||||
func (s *AgentService) findDirectParent(ctx context.Context, agentId string) (*model.Agent, error) {
|
||||
// 查找关系类型为1(直接关系)的上级
|
||||
builder := s.AgentRelationModel.SelectBuilder()
|
||||
builder = builder.Where("child_id = ? AND relation_type = ? AND del_state = ?", agentId, 1, globalkey.DelStateNo)
|
||||
@@ -692,7 +696,7 @@ func (s *AgentService) findDirectParent(ctx context.Context, agentId int64) (*mo
|
||||
// - 普通 -> 普通 -> 钻石:会找到钻石(跳过中间的普通代理)
|
||||
// - 普通 -> 黄金 -> 钻石:会找到钻石(跳过黄金代理)
|
||||
// - 普通 -> 普通 -> 黄金:返回 ErrNotFound(没有钻石)
|
||||
func (s *AgentService) findDiamondParent(ctx context.Context, agentId int64) (*model.Agent, error) {
|
||||
func (s *AgentService) findDiamondParent(ctx context.Context, agentId string) (*model.Agent, error) {
|
||||
currentId := agentId
|
||||
maxDepth := 100 // 防止无限循环
|
||||
depth := 0
|
||||
@@ -732,7 +736,7 @@ func (s *AgentService) findDiamondParent(ctx context.Context, agentId int64) (*m
|
||||
// - 普通 -> 普通 -> 黄金:会找到黄金(跳过中间的普通代理)
|
||||
// - 普通 -> 黄金:会找到黄金
|
||||
// - 普通 -> 普通 -> 钻石:返回 ErrNotFound(跳过钻石,继续查找黄金,但找不到)
|
||||
func (s *AgentService) findGoldParent(ctx context.Context, agentId int64) (*model.Agent, error) {
|
||||
func (s *AgentService) findGoldParent(ctx context.Context, agentId string) (*model.Agent, error) {
|
||||
currentId := agentId
|
||||
maxDepth := 100 // 防止无限循环
|
||||
depth := 0
|
||||
@@ -784,7 +788,7 @@ func (s *AgentService) getConfigInt(ctx context.Context, configKey string) (int6
|
||||
}
|
||||
|
||||
// ProcessUpgrade 处理代理升级
|
||||
func (s *AgentService) ProcessUpgrade(ctx context.Context, agentId, toLevel int64, upgradeType int64, upgradeFee, rebateAmount float64, orderNo string, operatorAgentId int64) error {
|
||||
func (s *AgentService) ProcessUpgrade(ctx context.Context, agentId string, toLevel int64, upgradeType int64, upgradeFee, rebateAmount float64, orderNo string, operatorAgentId string) error {
|
||||
return s.AgentWalletModel.Trans(ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||
// 1. 获取代理信息
|
||||
agent, err := s.AgentModel.FindOne(transCtx, agentId)
|
||||
@@ -820,7 +824,7 @@ func (s *AgentService) ProcessUpgrade(ctx context.Context, agentId, toLevel int6
|
||||
if needDetach {
|
||||
// 脱离前先获取原直接上级及其上级的信息(用于后续重新连接)
|
||||
oldParent, oldParentErr := s.findDirectParent(transCtx, agentId)
|
||||
var grandparentId int64 = 0
|
||||
var grandparentId string = ""
|
||||
if oldParentErr == nil && oldParent != nil {
|
||||
// 查找原上级的上级
|
||||
grandparent, grandparentErr := s.findDirectParent(transCtx, oldParent.Id)
|
||||
@@ -835,7 +839,7 @@ func (s *AgentService) ProcessUpgrade(ctx context.Context, agentId, toLevel int6
|
||||
}
|
||||
|
||||
// 脱离后,尝试连接到原上级的上级
|
||||
if grandparentId > 0 {
|
||||
if grandparentId != "" {
|
||||
if err := s.reconnectToGrandparent(transCtx, session, agentId, toLevel, grandparentId); err != nil {
|
||||
return errors.Wrapf(err, "重新连接上级关系失败")
|
||||
}
|
||||
@@ -844,7 +848,7 @@ func (s *AgentService) ProcessUpgrade(ctx context.Context, agentId, toLevel int6
|
||||
|
||||
// 5. 如果升级为钻石,独立成新团队
|
||||
if toLevel == 3 {
|
||||
agent.TeamLeaderId = sql.NullInt64{Int64: agentId, Valid: true}
|
||||
agent.TeamLeaderId = sql.NullString{String: agentId, Valid: true}
|
||||
// 更新所有下级的团队首领
|
||||
if err := s.updateChildrenTeamLeader(transCtx, session, agentId, agentId); err != nil {
|
||||
return errors.Wrapf(err, "更新下级团队首领失败")
|
||||
@@ -855,8 +859,8 @@ func (s *AgentService) ProcessUpgrade(ctx context.Context, agentId, toLevel int6
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return errors.Wrapf(err, "查找团队首领失败")
|
||||
}
|
||||
if teamLeaderId > 0 {
|
||||
agent.TeamLeaderId = sql.NullInt64{Int64: teamLeaderId, Valid: true}
|
||||
if teamLeaderId != "" {
|
||||
agent.TeamLeaderId = sql.NullString{String: teamLeaderId, Valid: true}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,7 +903,7 @@ func (s *AgentService) needDetachFromParent(ctx context.Context, agent *model.Ag
|
||||
}
|
||||
|
||||
// detachFromParent 脱离直接上级关系
|
||||
func (s *AgentService) detachFromParent(ctx context.Context, session sqlx.Session, agentId int64) error {
|
||||
func (s *AgentService) detachFromParent(ctx context.Context, session sqlx.Session, agentId string) error {
|
||||
// 查找直接关系
|
||||
builder := s.AgentRelationModel.SelectBuilder().
|
||||
Where("child_id = ? AND relation_type = ? AND del_state = ?", agentId, 1, globalkey.DelStateNo)
|
||||
@@ -926,7 +930,7 @@ func (s *AgentService) detachFromParent(ctx context.Context, session sqlx.Sessio
|
||||
}
|
||||
|
||||
// reconnectToGrandparent 重新连接到原上级的上级(如果存在且符合条件)
|
||||
func (s *AgentService) reconnectToGrandparent(ctx context.Context, session sqlx.Session, agentId int64, newLevel int64, grandparentId int64) error {
|
||||
func (s *AgentService) reconnectToGrandparent(ctx context.Context, session sqlx.Session, agentId string, newLevel int64, grandparentId string) error {
|
||||
// 获取原上级的上级信息
|
||||
grandparent, err := s.AgentModel.FindOne(ctx, grandparentId)
|
||||
if err != nil {
|
||||
@@ -967,11 +971,12 @@ func (s *AgentService) reconnectToGrandparent(ctx context.Context, session sqlx.
|
||||
}
|
||||
|
||||
// 创建新的关系连接到原上级的上级
|
||||
relation := &model.AgentRelation{
|
||||
ParentId: grandparent.Id,
|
||||
ChildId: agentId,
|
||||
RelationType: 1, // 直接关系
|
||||
}
|
||||
relation := &model.AgentRelation{
|
||||
Id: uuid.NewString(),
|
||||
ParentId: grandparent.Id,
|
||||
ChildId: agentId,
|
||||
RelationType: 1, // 直接关系
|
||||
}
|
||||
if _, err := s.AgentRelationModel.Insert(ctx, session, relation); err != nil {
|
||||
return errors.Wrapf(err, "创建新关系失败")
|
||||
}
|
||||
@@ -980,10 +985,10 @@ func (s *AgentService) reconnectToGrandparent(ctx context.Context, session sqlx.
|
||||
}
|
||||
|
||||
// updateChildrenTeamLeader 更新所有下级的团队首领
|
||||
func (s *AgentService) updateChildrenTeamLeader(ctx context.Context, session sqlx.Session, agentId, teamLeaderId int64) error {
|
||||
func (s *AgentService) updateChildrenTeamLeader(ctx context.Context, session sqlx.Session, agentId, teamLeaderId string) error {
|
||||
// 递归更新所有下级
|
||||
var updateChildren func(int64) error
|
||||
updateChildren = func(parentId int64) error {
|
||||
var updateChildren func(string) error
|
||||
updateChildren = func(parentId string) error {
|
||||
// 查找直接下级
|
||||
builder := s.AgentRelationModel.SelectBuilder().
|
||||
Where("parent_id = ? AND relation_type = ? AND del_state = ?", parentId, 1, globalkey.DelStateNo)
|
||||
@@ -998,9 +1003,9 @@ func (s *AgentService) updateChildrenTeamLeader(ctx context.Context, session sql
|
||||
continue
|
||||
}
|
||||
|
||||
child.TeamLeaderId = sql.NullInt64{Int64: teamLeaderId, Valid: true}
|
||||
child.TeamLeaderId = sql.NullString{String: teamLeaderId, Valid: true}
|
||||
if err := s.AgentModel.UpdateWithVersion(ctx, session, child); err != nil {
|
||||
return errors.Wrapf(err, "更新下级团队首领失败, childId: %d", child.Id)
|
||||
return errors.Wrapf(err, "更新下级团队首领失败, childId: %s", child.Id)
|
||||
}
|
||||
|
||||
// 递归更新下级的下级
|
||||
@@ -1016,24 +1021,24 @@ func (s *AgentService) updateChildrenTeamLeader(ctx context.Context, session sql
|
||||
}
|
||||
|
||||
// findTeamLeaderId 查找团队首领ID(钻石代理)
|
||||
func (s *AgentService) findTeamLeaderId(ctx context.Context, agentId int64) (int64, error) {
|
||||
func (s *AgentService) findTeamLeaderId(ctx context.Context, agentId string) (string, error) {
|
||||
diamondParent, err := s.findDiamondParent(ctx, agentId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return 0, nil
|
||||
return "", nil
|
||||
}
|
||||
return 0, err
|
||||
return "", err
|
||||
}
|
||||
return diamondParent.Id, nil
|
||||
}
|
||||
|
||||
// giveRebateForUpgrade 发放升级返佣
|
||||
// 注意:升级返佣信息记录在 agent_upgrade 表中(rebate_agent_id 和 rebate_amount),不需要在 agent_rebate 表中创建记录
|
||||
func (s *AgentService) giveRebateForUpgrade(ctx context.Context, session sqlx.Session, parentAgentId, upgradeAgentId int64, amount float64, orderNo string) error {
|
||||
func (s *AgentService) giveRebateForUpgrade(ctx context.Context, session sqlx.Session, parentAgentId, upgradeAgentId string, amount float64, orderNo string) error {
|
||||
// 更新钱包余额
|
||||
wallet, err := s.AgentWalletModel.FindOneByAgentId(ctx, parentAgentId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查询钱包失败, agentId: %d", parentAgentId)
|
||||
return errors.Wrapf(err, "查询钱包失败, agentId: %s", parentAgentId)
|
||||
}
|
||||
|
||||
wallet.Balance += amount
|
||||
|
||||
Reference in New Issue
Block a user