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 * 1. PROVINCE_COMPANY
* 2. benefitActive=true * 2. benefitActive=true
* 3. benefitActive=false * 3. benefitActive=false
* - (5)
* -
* -
* 4.
*/ */
async getProvinceAreaRewardDistribution( async getProvinceAreaRewardDistribution(
provinceCode: string, provinceCode: string,
@ -1282,7 +1286,21 @@ export class AuthorizationApplicationService {
// 查找该省份的正式省公司 // 查找该省份的正式省公司
const provinceCompany = await this.authorizationRepository.findProvinceCompanyByRegion(provinceCode) 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 { return {
distributions: [ 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 { this.logger.debug(
distributions: [ `[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, accountSequence: systemProvinceAccountId,
treeCount, treeCount,
reason, reason: `初始考核中(${currentTeamCount}+${treeCount}=${afterPlantingCount}/${initialTarget}),进系统省账户`,
isSystemAccount: true, 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 * 1. CITY_COMPANY
* 2. benefitActive=true * 2. benefitActive=true
* 3. benefitActive=false * 3. benefitActive=false
* - (1)
* -
* -
* 4.
*/ */
async getCityAreaRewardDistribution( async getCityAreaRewardDistribution(
cityCode: string, cityCode: string,
@ -1508,7 +1588,21 @@ export class AuthorizationApplicationService {
// 查找该城市的正式市公司 // 查找该城市的正式市公司
const cityCompany = await this.authorizationRepository.findCityCompanyByRegion(cityCode) 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 { return {
distributions: [ 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 { this.logger.debug(
distributions: [ `[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, accountSequence: systemCityAccountId,
treeCount, treeCount,
reason, reason: `初始考核中(${currentTeamCount}+${treeCount}=${afterPlantingCount}/${initialTarget}),进系统市账户`,
isSystemAccount: true, 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 { static forProvince(): AssessmentConfig {
return new AssessmentConfig(0, MonthlyTargetType.NONE) return new AssessmentConfig(50000, MonthlyTargetType.LADDER) // 省区域5万棵
} }
static forAuthCity(): AssessmentConfig { static forAuthCity(): AssessmentConfig {
@ -23,6 +23,6 @@ export class AssessmentConfig {
} }
static forCity(): AssessmentConfig { static forCity(): AssessmentConfig {
return new AssessmentConfig(0, MonthlyTargetType.NONE) return new AssessmentConfig(10000, MonthlyTargetType.LADDER) // 市区域1万棵
} }
} }