This commit is contained in:
2025-12-09 18:55:28 +08:00
parent 8d00d67540
commit c23ab8338b
209 changed files with 5445 additions and 3963 deletions

View File

@@ -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