feat(authorization): 提高社区和市团队权益初始激活门槛
社区初始激活门槛: 10棵 → 100棵 市团队初始激活门槛: 100棵 → 500棵 变更说明: - 仅调整初始激活门槛,月度考核目标不变(社区仍为10棵/月,市团队仍为100棵/月) - 已激活用户不受影响(祖父条款),仅对新申请的授权生效 - 激活逻辑通过 AssessmentConfig 工厂方法动态获取门槛值,无需修改业务代码 - 数据库已有记录的 initialTargetTreeCount 保持旧值不变 修改文件: - assessment-config.vo.ts: 核心门槛配置 - authorization-application.service.ts: 同步注释 - authorization-role.aggregate.spec.ts: 同步测试断言 - DEVELOPMENT_GUIDE.md: 同步文档描述 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
eda39b982d
commit
eacdfddff8
|
|
@ -53,8 +53,8 @@ Authorization Service 是 RWA 榴莲皇后平台的授权管理微服务,负
|
||||||
- 市公司团队权益:40 USDT/棵
|
- 市公司团队权益:40 USDT/棵
|
||||||
|
|
||||||
初始考核:
|
初始考核:
|
||||||
- 伞下团队认种总量达到100棵后权益自动生效
|
- 伞下团队认种总量达到500棵后权益自动生效
|
||||||
- 考核的100棵权益归上级市公司所有(无上级则归总部社区账户)
|
- 考核的500棵权益归上级市公司所有(无上级则归总部社区账户)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. 正式省公司授权
|
### 3. 正式省公司授权
|
||||||
|
|
@ -92,8 +92,8 @@ Authorization Service 是 RWA 榴莲皇后平台的授权管理微服务,负
|
||||||
- 社区权益:80 USDT/棵
|
- 社区权益:80 USDT/棵
|
||||||
|
|
||||||
初始考核:
|
初始考核:
|
||||||
- 伞下团队认种总量达到10棵后权益自动生效
|
- 伞下团队认种总量达到100棵后权益自动生效
|
||||||
- 考核的10棵权益归上级社区所有(无上级则归总部社区账户)
|
- 考核的100棵权益归上级社区所有(无上级则归总部社区账户)
|
||||||
|
|
||||||
月度考核:
|
月度考核:
|
||||||
- 每月需新增10棵
|
- 每月需新增10棵
|
||||||
|
|
@ -1891,7 +1891,7 @@ export class AuthorizationApplicationService {
|
||||||
communityName: command.communityName
|
communityName: command.communityName
|
||||||
})
|
})
|
||||||
|
|
||||||
// 3. 检查初始考核(10棵)
|
// 3. 检查初始考核(100棵)
|
||||||
const teamStats = await this.statsRepository.findByUserId(userId)
|
const teamStats = await this.statsRepository.findByUserId(userId)
|
||||||
const totalTreeCount = teamStats?.totalTeamPlantingCount || 0
|
const totalTreeCount = teamStats?.totalTeamPlantingCount || 0
|
||||||
|
|
||||||
|
|
@ -2005,7 +2005,7 @@ export class AuthorizationApplicationService {
|
||||||
cityName: command.cityName
|
cityName: command.cityName
|
||||||
})
|
})
|
||||||
|
|
||||||
// 3. 检查初始考核(100棵)
|
// 3. 检查初始考核(500棵)
|
||||||
const teamStats = await this.statsRepository.findByUserId(userId)
|
const teamStats = await this.statsRepository.findByUserId(userId)
|
||||||
const totalTreeCount = teamStats?.totalTeamPlantingCount || 0
|
const totalTreeCount = teamStats?.totalTeamPlantingCount || 0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ export class AuthorizationApplicationService {
|
||||||
communityName: command.communityName,
|
communityName: command.communityName,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 3. 检查初始考核(10棵)- 使用下级团队认种数(不含自己)
|
// 3. 检查初始考核(100棵)- 使用下级团队认种数(不含自己)
|
||||||
const teamStats = await this.statsRepository.findByAccountSequence(userId.accountSequence)
|
const teamStats = await this.statsRepository.findByAccountSequence(userId.accountSequence)
|
||||||
const subordinateTreeCount = teamStats?.subordinateTeamPlantingCount || 0
|
const subordinateTreeCount = teamStats?.subordinateTeamPlantingCount || 0
|
||||||
|
|
||||||
|
|
@ -212,7 +212,7 @@ export class AuthorizationApplicationService {
|
||||||
cityName: command.cityName,
|
cityName: command.cityName,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 3. 检查初始考核(100棵)- 使用下级团队认种数(不含自己)
|
// 3. 检查初始考核(500棵)- 使用下级团队认种数(不含自己)
|
||||||
const teamStats = await this.statsRepository.findByAccountSequence(userId.accountSequence)
|
const teamStats = await this.statsRepository.findByAccountSequence(userId.accountSequence)
|
||||||
const subordinateTreeCount = teamStats?.subordinateTeamPlantingCount || 0
|
const subordinateTreeCount = teamStats?.subordinateTeamPlantingCount || 0
|
||||||
|
|
||||||
|
|
@ -1175,7 +1175,7 @@ export class AuthorizationApplicationService {
|
||||||
*
|
*
|
||||||
* 业务规则:
|
* 业务规则:
|
||||||
* - 从当前社区开始,往上找到所有已授权且权益已激活的社区
|
* - 从当前社区开始,往上找到所有已授权且权益已激活的社区
|
||||||
* - 将它们的权益都停用,重新开始10棵树的初始考核
|
* - 将它们的权益都停用,重新开始100棵树的初始考核
|
||||||
* - 总部社区不受影响
|
* - 总部社区不受影响
|
||||||
*
|
*
|
||||||
* @param accountSequence 月度考核失败的社区的 accountSequence
|
* @param accountSequence 月度考核失败的社区的 accountSequence
|
||||||
|
|
@ -1307,7 +1307,7 @@ export class AuthorizationApplicationService {
|
||||||
*
|
*
|
||||||
* 业务规则:
|
* 业务规则:
|
||||||
* - 从当前市团队授权开始,往上找到所有已授权且权益已激活的市团队授权
|
* - 从当前市团队授权开始,往上找到所有已授权且权益已激活的市团队授权
|
||||||
* - 将它们的权益都停用,重新开始100棵树的初始考核
|
* - 将它们的权益都停用,重新开始500棵树的初始考核
|
||||||
*/
|
*/
|
||||||
async cascadeDeactivateAuthCityBenefits(
|
async cascadeDeactivateAuthCityBenefits(
|
||||||
accountSequence: string,
|
accountSequence: string,
|
||||||
|
|
@ -2064,7 +2064,7 @@ export class AuthorizationApplicationService {
|
||||||
* 1. 找到认种用户推荐链上最近的社区
|
* 1. 找到认种用户推荐链上最近的社区
|
||||||
* 2. 如果该社区 benefitActive=true,全部权益给该社区
|
* 2. 如果该社区 benefitActive=true,全部权益给该社区
|
||||||
* 3. 如果该社区 benefitActive=false:
|
* 3. 如果该社区 benefitActive=false:
|
||||||
* - 计算该社区还需要多少棵才能达到初始考核(10棵)
|
* - 计算该社区还需要多少棵才能达到初始考核(100棵)
|
||||||
* - 考核前的部分给上级社区或总部
|
* - 考核前的部分给上级社区或总部
|
||||||
* - 考核后的部分给该社区(同时激活权益)
|
* - 考核后的部分给该社区(同时激活权益)
|
||||||
* 4. 如果没有社区,全部给总部
|
* 4. 如果没有社区,全部给总部
|
||||||
|
|
@ -2179,7 +2179,7 @@ export class AuthorizationApplicationService {
|
||||||
// 注意:如果 referral-service 还没处理完,rawSubordinateCount 可能还是旧值,
|
// 注意:如果 referral-service 还没处理完,rawSubordinateCount 可能还是旧值,
|
||||||
// 此时 currentTeamCount 可能为负数,需要取 max(0, ...)
|
// 此时 currentTeamCount 可能为负数,需要取 max(0, ...)
|
||||||
const currentTeamCount = Math.max(0, rawSubordinateCount - treeCount)
|
const currentTeamCount = Math.max(0, rawSubordinateCount - treeCount)
|
||||||
const initialTarget = nearestCommunity.getInitialTarget() // 社区初始考核目标:10棵
|
const initialTarget = nearestCommunity.getInitialTarget() // 社区初始考核目标:100棵
|
||||||
|
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`[getCommunityRewardDistribution] Community ${nearestCommunity.userId.accountSequence} ` +
|
`[getCommunityRewardDistribution] Community ${nearestCommunity.userId.accountSequence} ` +
|
||||||
|
|
@ -2229,8 +2229,8 @@ export class AuthorizationApplicationService {
|
||||||
} else {
|
} else {
|
||||||
// 未达标,需要拆分
|
// 未达标,需要拆分
|
||||||
// toReachTarget: 还差多少棵达到考核目标(包括达标那一棵)
|
// toReachTarget: 还差多少棵达到考核目标(包括达标那一棵)
|
||||||
// 业务规则:第1-10棵全部给上级的上级/总部,第11棵开始才给该社区
|
// 业务规则:第1-100棵全部给上级的上级/总部,第101棵开始才给该社区
|
||||||
// 例如:目标10棵,当前2棵 -> toReachTarget = 8(第3-10棵给上级,第11棵开始给自己)
|
// 例如:目标100棵,当前20棵 -> toReachTarget = 80(第21-100棵给上级,第101棵开始给自己)
|
||||||
const toReachTarget = Math.max(0, initialTarget - currentTeamCount)
|
const toReachTarget = Math.max(0, initialTarget - currentTeamCount)
|
||||||
const afterPlantingCount = currentTeamCount + treeCount // 本次认种后的总数
|
const afterPlantingCount = currentTeamCount + treeCount // 本次认种后的总数
|
||||||
|
|
||||||
|
|
@ -2248,7 +2248,7 @@ export class AuthorizationApplicationService {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 本次认种跨越考核达标点 (afterPlantingCount > initialTarget)
|
// 本次认种跨越考核达标点 (afterPlantingCount > initialTarget)
|
||||||
// 达标前的部分(包括第10棵)给上级/总部
|
// 达标前的部分(包括第100棵)给上级/总部
|
||||||
if (toReachTarget > 0) {
|
if (toReachTarget > 0) {
|
||||||
distributions.push({
|
distributions.push({
|
||||||
accountSequence: parentCommunityAccountSequence,
|
accountSequence: parentCommunityAccountSequence,
|
||||||
|
|
@ -2256,7 +2256,7 @@ export class AuthorizationApplicationService {
|
||||||
reason: `初始考核(${currentTeamCount}+${toReachTarget}=${initialTarget}/${initialTarget}),${parentCommunityReason}`,
|
reason: `初始考核(${currentTeamCount}+${toReachTarget}=${initialTarget}/${initialTarget}),${parentCommunityReason}`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 超过达标点的部分(第11棵开始),给该社区
|
// 超过达标点的部分(第101棵开始),给该社区
|
||||||
const afterTargetCount = treeCount - toReachTarget
|
const afterTargetCount = treeCount - toReachTarget
|
||||||
if (afterTargetCount > 0) {
|
if (afterTargetCount > 0) {
|
||||||
distributions.push({
|
distributions.push({
|
||||||
|
|
@ -2635,7 +2635,7 @@ export class AuthorizationApplicationService {
|
||||||
* 1. 找到认种用户推荐链上最近的授权市公司(AUTH_CITY_COMPANY)
|
* 1. 找到认种用户推荐链上最近的授权市公司(AUTH_CITY_COMPANY)
|
||||||
* 2. 如果该授权市公司 benefitActive=true,全部权益给该用户
|
* 2. 如果该授权市公司 benefitActive=true,全部权益给该用户
|
||||||
* 3. 如果该授权市公司 benefitActive=false:
|
* 3. 如果该授权市公司 benefitActive=false:
|
||||||
* - 计算还需要多少棵才能达到初始考核(100棵)
|
* - 计算还需要多少棵才能达到初始考核(500棵)
|
||||||
* - 考核前的部分给上级/总部
|
* - 考核前的部分给上级/总部
|
||||||
* - 考核后的部分给该用户
|
* - 考核后的部分给该用户
|
||||||
* 4. 如果没有授权市公司,全部给总部
|
* 4. 如果没有授权市公司,全部给总部
|
||||||
|
|
@ -2726,7 +2726,7 @@ export class AuthorizationApplicationService {
|
||||||
const rawSubordinateCount = stats?.subordinateTeamPlantingCount ?? 0
|
const rawSubordinateCount = stats?.subordinateTeamPlantingCount ?? 0
|
||||||
// 修复竞态条件:减去本次认种数量来还原"认种前"的下级团队数
|
// 修复竞态条件:减去本次认种数量来还原"认种前"的下级团队数
|
||||||
const currentTeamCount = Math.max(0, rawSubordinateCount - treeCount)
|
const currentTeamCount = Math.max(0, rawSubordinateCount - treeCount)
|
||||||
const initialTarget = nearestAuthCity.getInitialTarget() // 100棵
|
const initialTarget = nearestAuthCity.getInitialTarget() // 500棵
|
||||||
|
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`[getCityTeamRewardDistribution] rawSubordinateCount=${rawSubordinateCount}, treeCount=${treeCount}, currentTeamCount(before)=${currentTeamCount}`,
|
`[getCityTeamRewardDistribution] rawSubordinateCount=${rawSubordinateCount}, treeCount=${treeCount}, currentTeamCount(before)=${currentTeamCount}`,
|
||||||
|
|
@ -2786,7 +2786,7 @@ export class AuthorizationApplicationService {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 本次认种跨越考核达标点 (afterPlantingCount > initialTarget)
|
// 本次认种跨越考核达标点 (afterPlantingCount > initialTarget)
|
||||||
// 达标前的部分(包括第100棵)给上级/总部
|
// 达标前的部分(包括第500棵)给上级/总部
|
||||||
if (toReachTarget > 0) {
|
if (toReachTarget > 0) {
|
||||||
distributions.push({
|
distributions.push({
|
||||||
accountSequence: parentAccountSequence,
|
accountSequence: parentAccountSequence,
|
||||||
|
|
@ -2794,7 +2794,7 @@ export class AuthorizationApplicationService {
|
||||||
reason: `初始考核(${currentTeamCount}+${toReachTarget}=${initialTarget}/${initialTarget}),${parentReason}`,
|
reason: `初始考核(${currentTeamCount}+${toReachTarget}=${initialTarget}/${initialTarget}),${parentReason}`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 超过达标点的部分(第101棵开始),给该市团队
|
// 超过达标点的部分(第501棵开始),给该市团队
|
||||||
const afterTargetCount = treeCount - toReachTarget
|
const afterTargetCount = treeCount - toReachTarget
|
||||||
if (afterTargetCount > 0) {
|
if (afterTargetCount > 0) {
|
||||||
distributions.push({
|
distributions.push({
|
||||||
|
|
@ -3467,7 +3467,7 @@ export class AuthorizationApplicationService {
|
||||||
cityName: command.cityName!,
|
cityName: command.cityName!,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 检查初始考核(100棵)
|
// 检查初始考核(500棵)
|
||||||
const teamStats = await this.statsRepository.findByAccountSequence(command.accountSequence)
|
const teamStats = await this.statsRepository.findByAccountSequence(command.accountSequence)
|
||||||
const subordinateTreeCount = teamStats?.subordinateTeamPlantingCount || 0
|
const subordinateTreeCount = teamStats?.subordinateTeamPlantingCount || 0
|
||||||
if (subordinateTreeCount >= authorization.getInitialTarget()) {
|
if (subordinateTreeCount >= authorization.getInitialTarget()) {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ describe('AuthorizationRole Aggregate', () => {
|
||||||
expect(auth.status).toBe(AuthorizationStatus.PENDING)
|
expect(auth.status).toBe(AuthorizationStatus.PENDING)
|
||||||
expect(auth.displayTitle).toBe('量子社区')
|
expect(auth.displayTitle).toBe('量子社区')
|
||||||
expect(auth.benefitActive).toBe(false)
|
expect(auth.benefitActive).toBe(false)
|
||||||
expect(auth.getInitialTarget()).toBe(10)
|
expect(auth.getInitialTarget()).toBe(100)
|
||||||
expect(auth.domainEvents.length).toBe(1)
|
expect(auth.domainEvents.length).toBe(1)
|
||||||
expect(auth.domainEvents[0].eventType).toBe('authorization.community.requested')
|
expect(auth.domainEvents[0].eventType).toBe('authorization.community.requested')
|
||||||
})
|
})
|
||||||
|
|
@ -51,7 +51,7 @@ describe('AuthorizationRole Aggregate', () => {
|
||||||
expect(auth.status).toBe(AuthorizationStatus.PENDING)
|
expect(auth.status).toBe(AuthorizationStatus.PENDING)
|
||||||
expect(auth.displayTitle).toBe('授权长沙市')
|
expect(auth.displayTitle).toBe('授权长沙市')
|
||||||
expect(auth.benefitActive).toBe(false)
|
expect(auth.benefitActive).toBe(false)
|
||||||
expect(auth.getInitialTarget()).toBe(100)
|
expect(auth.getInitialTarget()).toBe(500)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ export class AssessmentConfig {
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
static forCommunity(): AssessmentConfig {
|
static forCommunity(): AssessmentConfig {
|
||||||
return new AssessmentConfig(10, MonthlyTargetType.FIXED)
|
return new AssessmentConfig(100, MonthlyTargetType.FIXED)
|
||||||
}
|
}
|
||||||
|
|
||||||
static forAuthProvince(): AssessmentConfig {
|
static forAuthProvince(): AssessmentConfig {
|
||||||
|
|
@ -19,7 +19,7 @@ export class AssessmentConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
static forAuthCity(): AssessmentConfig {
|
static forAuthCity(): AssessmentConfig {
|
||||||
return new AssessmentConfig(100, MonthlyTargetType.LADDER)
|
return new AssessmentConfig(500, MonthlyTargetType.LADDER)
|
||||||
}
|
}
|
||||||
|
|
||||||
static forCity(): AssessmentConfig {
|
static forCity(): AssessmentConfig {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue