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:
parent
905725fc2d
commit
4bf4efb1f4
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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万棵
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue