feat(authorization): add assessment rules for province/city area roles

- Province area (PROVINCE_COMPANY): 50,000 trees initial target
- City area (CITY_COMPANY): 10,000 trees initial target
- Apply consistent assessment logic: pre-target rewards go to system account, post-target rewards go to company
- Auto-activate benefit when target is reached

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2025-12-11 21:57:00 -08:00
parent 905725fc2d
commit 4bf4efb1f4
2 changed files with 178 additions and 26 deletions

View File

@ -1259,7 +1259,11 @@ export class AuthorizationApplicationService {
*
* 1. PROVINCE_COMPANY
* 2. benefitActive=true
* 3. benefitActive=false
* 3. benefitActive=false
* - (5)
* -
* -
* 4.
*/
async getProvinceAreaRewardDistribution(
provinceCode: string,
@ -1282,7 +1286,21 @@ export class AuthorizationApplicationService {
// 查找该省份的正式省公司
const provinceCompany = await this.authorizationRepository.findProvinceCompanyByRegion(provinceCode)
if (provinceCompany && provinceCompany.benefitActive) {
if (!provinceCompany) {
// 无正式省公司,全部进系统省账户
return {
distributions: [
{
accountSequence: systemProvinceAccountId,
treeCount,
reason: '无正式省公司授权,进系统省账户',
isSystemAccount: true,
},
],
}
}
if (provinceCompany.benefitActive) {
// 正式省公司权益已激活,进该省公司账户
return {
distributions: [
@ -1296,21 +1314,79 @@ export class AuthorizationApplicationService {
}
}
// 无正式省公司或权益未激活,进系统省账户
const reason = provinceCompany
? `省区域权益未激活(考核中),进系统省账户`
: '无正式省公司授权,进系统省账户'
// 权益未激活,计算考核分配 - 使用下级团队认种数(不含自己)
const stats = await this.statsRepository.findByAccountSequence(provinceCompany.userId.accountSequence)
const rawSubordinateCount = stats?.subordinateTeamPlantingCount ?? 0
// 修复竞态条件:减去本次认种数量来还原"认种前"的下级团队数
const currentTeamCount = Math.max(0, rawSubordinateCount - treeCount)
const initialTarget = provinceCompany.getInitialTarget() // 5万棵
return {
distributions: [
{
this.logger.debug(
`[getProvinceAreaRewardDistribution] rawSubordinateCount=${rawSubordinateCount}, treeCount=${treeCount}, currentTeamCount(before)=${currentTeamCount}, initialTarget=${initialTarget}`,
)
const distributions: Array<{
accountSequence: number
treeCount: number
reason: string
isSystemAccount: boolean
}> = []
if (currentTeamCount >= initialTarget) {
// 已达标但权益未激活,全部给该省公司
distributions.push({
accountSequence: Number(provinceCompany.userId.accountSequence),
treeCount,
reason: '已达初始考核目标',
isSystemAccount: false,
})
// 自动激活权益
await this.tryActivateBenefit(provinceCompany)
} else {
const remaining = initialTarget - currentTeamCount
const afterPlantingCount = currentTeamCount + treeCount
if (afterPlantingCount < initialTarget) {
// 本次认种后仍未达标,全部进系统省账户
distributions.push({
accountSequence: systemProvinceAccountId,
treeCount,
reason,
reason: `初始考核中(${currentTeamCount}+${treeCount}=${afterPlantingCount}/${initialTarget}),进系统省账户`,
isSystemAccount: true,
},
],
})
} else if (afterPlantingCount === initialTarget) {
// 本次认种恰好达标,全部进系统省账户,但需要激活权益
distributions.push({
accountSequence: systemProvinceAccountId,
treeCount,
reason: `初始考核达标(${currentTeamCount}+${treeCount}=${initialTarget}),进系统省账户`,
isSystemAccount: true,
})
// 自动激活权益
await this.tryActivateBenefit(provinceCompany)
} else {
// 本次认种跨越考核达标点
// 考核前的部分进系统省账户
distributions.push({
accountSequence: systemProvinceAccountId,
treeCount: remaining,
reason: `初始考核(${currentTeamCount}+${remaining}=${initialTarget}),进系统省账户`,
isSystemAccount: true,
})
// 考核后的部分给该省公司
distributions.push({
accountSequence: Number(provinceCompany.userId.accountSequence),
treeCount: treeCount - remaining,
reason: '考核达标后权益生效',
isSystemAccount: false,
})
// 自动激活权益
await this.tryActivateBenefit(provinceCompany)
}
}
this.logger.debug(`[getProvinceAreaRewardDistribution] Result: ${JSON.stringify(distributions)}`)
return { distributions }
}
/**
@ -1485,7 +1561,11 @@ export class AuthorizationApplicationService {
*
* 1. CITY_COMPANY
* 2. benefitActive=true
* 3. benefitActive=false
* 3. benefitActive=false
* - (1)
* -
* -
* 4.
*/
async getCityAreaRewardDistribution(
cityCode: string,
@ -1508,7 +1588,21 @@ export class AuthorizationApplicationService {
// 查找该城市的正式市公司
const cityCompany = await this.authorizationRepository.findCityCompanyByRegion(cityCode)
if (cityCompany && cityCompany.benefitActive) {
if (!cityCompany) {
// 无正式市公司,全部进系统市账户
return {
distributions: [
{
accountSequence: systemCityAccountId,
treeCount,
reason: '无正式市公司授权,进系统市账户',
isSystemAccount: true,
},
],
}
}
if (cityCompany.benefitActive) {
// 正式市公司权益已激活,进该市公司账户
return {
distributions: [
@ -1522,20 +1616,78 @@ export class AuthorizationApplicationService {
}
}
// 无正式市公司或权益未激活,进系统市账户
const reason = cityCompany
? `市区域权益未激活(考核中),进系统市账户`
: '无正式市公司授权,进系统市账户'
// 权益未激活,计算考核分配 - 使用下级团队认种数(不含自己)
const stats = await this.statsRepository.findByAccountSequence(cityCompany.userId.accountSequence)
const rawSubordinateCount = stats?.subordinateTeamPlantingCount ?? 0
// 修复竞态条件:减去本次认种数量来还原"认种前"的下级团队数
const currentTeamCount = Math.max(0, rawSubordinateCount - treeCount)
const initialTarget = cityCompany.getInitialTarget() // 1万棵
return {
distributions: [
{
this.logger.debug(
`[getCityAreaRewardDistribution] rawSubordinateCount=${rawSubordinateCount}, treeCount=${treeCount}, currentTeamCount(before)=${currentTeamCount}, initialTarget=${initialTarget}`,
)
const distributions: Array<{
accountSequence: number
treeCount: number
reason: string
isSystemAccount: boolean
}> = []
if (currentTeamCount >= initialTarget) {
// 已达标但权益未激活,全部给该市公司
distributions.push({
accountSequence: Number(cityCompany.userId.accountSequence),
treeCount,
reason: '已达初始考核目标',
isSystemAccount: false,
})
// 自动激活权益
await this.tryActivateBenefit(cityCompany)
} else {
const remaining = initialTarget - currentTeamCount
const afterPlantingCount = currentTeamCount + treeCount
if (afterPlantingCount < initialTarget) {
// 本次认种后仍未达标,全部进系统市账户
distributions.push({
accountSequence: systemCityAccountId,
treeCount,
reason,
reason: `初始考核中(${currentTeamCount}+${treeCount}=${afterPlantingCount}/${initialTarget}),进系统市账户`,
isSystemAccount: true,
},
],
})
} else if (afterPlantingCount === initialTarget) {
// 本次认种恰好达标,全部进系统市账户,但需要激活权益
distributions.push({
accountSequence: systemCityAccountId,
treeCount,
reason: `初始考核达标(${currentTeamCount}+${treeCount}=${initialTarget}),进系统市账户`,
isSystemAccount: true,
})
// 自动激活权益
await this.tryActivateBenefit(cityCompany)
} else {
// 本次认种跨越考核达标点
// 考核前的部分进系统市账户
distributions.push({
accountSequence: systemCityAccountId,
treeCount: remaining,
reason: `初始考核(${currentTeamCount}+${remaining}=${initialTarget}),进系统市账户`,
isSystemAccount: true,
})
// 考核后的部分给该市公司
distributions.push({
accountSequence: Number(cityCompany.userId.accountSequence),
treeCount: treeCount - remaining,
reason: '考核达标后权益生效',
isSystemAccount: false,
})
// 自动激活权益
await this.tryActivateBenefit(cityCompany)
}
}
this.logger.debug(`[getCityAreaRewardDistribution] Result: ${JSON.stringify(distributions)}`)
return { distributions }
}
}

View File

@ -15,7 +15,7 @@ export class AssessmentConfig {
}
static forProvince(): AssessmentConfig {
return new AssessmentConfig(0, MonthlyTargetType.NONE)
return new AssessmentConfig(50000, MonthlyTargetType.LADDER) // 省区域5万棵
}
static forAuthCity(): AssessmentConfig {
@ -23,6 +23,6 @@ export class AssessmentConfig {
}
static forCity(): AssessmentConfig {
return new AssessmentConfig(0, MonthlyTargetType.NONE)
return new AssessmentConfig(10000, MonthlyTargetType.LADDER) // 市区域1万棵
}
}