rwadurian/backend/services/authorization-service/src/domain/aggregates/authorization-role.aggregat...

730 lines
22 KiB
TypeScript

import { AggregateRoot } from './aggregate-root.base'
import {
AuthorizationId,
UserId,
AdminUserId,
RegionCode,
AssessmentConfig,
} from '@/domain/value-objects'
import { RoleType, AuthorizationStatus, MonthlyTargetType } from '@/domain/enums'
import { DomainError } from '@/shared/exceptions'
import {
CommunityAuthorizedEvent,
CommunityAuthRequestedEvent,
AuthProvinceCompanyRequestedEvent,
AuthCityCompanyRequestedEvent,
AuthProvinceCompanyGrantedEvent,
AuthCityCompanyGrantedEvent,
ProvinceCompanyAuthorizedEvent,
CityCompanyAuthorizedEvent,
BenefitActivatedEvent,
BenefitDeactivatedEvent,
RoleAuthorizedEvent,
RoleRevokedEvent,
PercentageCheckExemptedEvent,
} from '@/domain/events'
export interface AuthorizationRoleProps {
authorizationId: AuthorizationId
userId: UserId
roleType: RoleType
regionCode: RegionCode
regionName: string
status: AuthorizationStatus
displayTitle: string
authorizedAt: Date | null
authorizedBy: AdminUserId | null
revokedAt: Date | null
revokedBy: AdminUserId | null
revokeReason: string | null
assessmentConfig: AssessmentConfig
requireLocalPercentage: number
exemptFromPercentageCheck: boolean
benefitActive: boolean
benefitActivatedAt: Date | null
benefitDeactivatedAt: Date | null
currentMonthIndex: number
createdAt: Date
updatedAt: Date
}
export class AuthorizationRole extends AggregateRoot {
private _authorizationId: AuthorizationId
private _userId: UserId
private _roleType: RoleType
private _regionCode: RegionCode
private _regionName: string
private _status: AuthorizationStatus
private _displayTitle: string
// 授权信息
private _authorizedAt: Date | null
private _authorizedBy: AdminUserId | null
private _revokedAt: Date | null
private _revokedBy: AdminUserId | null
private _revokeReason: string | null
// 考核配置
private _assessmentConfig: AssessmentConfig
// 自有团队占比
private _requireLocalPercentage: number
private _exemptFromPercentageCheck: boolean
// 权益状态
private _benefitActive: boolean
private _benefitActivatedAt: Date | null
private _benefitDeactivatedAt: Date | null
// 当前考核月份索引
private _currentMonthIndex: number
private _createdAt: Date
private _updatedAt: Date
// Getters
get authorizationId(): AuthorizationId {
return this._authorizationId
}
get userId(): UserId {
return this._userId
}
get roleType(): RoleType {
return this._roleType
}
get regionCode(): RegionCode {
return this._regionCode
}
get regionName(): string {
return this._regionName
}
get status(): AuthorizationStatus {
return this._status
}
get displayTitle(): string {
return this._displayTitle
}
get authorizedAt(): Date | null {
return this._authorizedAt
}
get authorizedBy(): AdminUserId | null {
return this._authorizedBy
}
get revokedAt(): Date | null {
return this._revokedAt
}
get revokedBy(): AdminUserId | null {
return this._revokedBy
}
get revokeReason(): string | null {
return this._revokeReason
}
get assessmentConfig(): AssessmentConfig {
return this._assessmentConfig
}
get requireLocalPercentage(): number {
return this._requireLocalPercentage
}
get exemptFromPercentageCheck(): boolean {
return this._exemptFromPercentageCheck
}
get benefitActive(): boolean {
return this._benefitActive
}
get benefitActivatedAt(): Date | null {
return this._benefitActivatedAt
}
get benefitDeactivatedAt(): Date | null {
return this._benefitDeactivatedAt
}
get currentMonthIndex(): number {
return this._currentMonthIndex
}
get createdAt(): Date {
return this._createdAt
}
get updatedAt(): Date {
return this._updatedAt
}
get isActive(): boolean {
return this._status === AuthorizationStatus.AUTHORIZED
}
// 私有构造函数
private constructor(props: AuthorizationRoleProps) {
super()
this._authorizationId = props.authorizationId
this._userId = props.userId
this._roleType = props.roleType
this._regionCode = props.regionCode
this._regionName = props.regionName
this._status = props.status
this._displayTitle = props.displayTitle
this._authorizedAt = props.authorizedAt
this._authorizedBy = props.authorizedBy
this._revokedAt = props.revokedAt
this._revokedBy = props.revokedBy
this._revokeReason = props.revokeReason
this._assessmentConfig = props.assessmentConfig
this._requireLocalPercentage = props.requireLocalPercentage
this._exemptFromPercentageCheck = props.exemptFromPercentageCheck
this._benefitActive = props.benefitActive
this._benefitActivatedAt = props.benefitActivatedAt
this._benefitDeactivatedAt = props.benefitDeactivatedAt
this._currentMonthIndex = props.currentMonthIndex
this._createdAt = props.createdAt
this._updatedAt = props.updatedAt
}
// 工厂方法 - 从数据库重建
static fromPersistence(props: AuthorizationRoleProps): AuthorizationRole {
return new AuthorizationRole(props)
}
// 工厂方法 - 创建社区授权
static createCommunityAuth(params: { userId: UserId; communityName: string }): AuthorizationRole {
const auth = new AuthorizationRole({
authorizationId: AuthorizationId.generate(),
userId: params.userId,
roleType: RoleType.COMMUNITY,
regionCode: RegionCode.create(params.communityName),
regionName: params.communityName,
status: AuthorizationStatus.PENDING,
displayTitle: params.communityName,
authorizedAt: null,
authorizedBy: null,
revokedAt: null,
revokedBy: null,
revokeReason: null,
assessmentConfig: AssessmentConfig.forCommunity(),
requireLocalPercentage: 0,
exemptFromPercentageCheck: true,
benefitActive: false,
benefitActivatedAt: null,
benefitDeactivatedAt: null,
currentMonthIndex: 0,
createdAt: new Date(),
updatedAt: new Date(),
})
auth.addDomainEvent(
new CommunityAuthRequestedEvent({
authorizationId: auth.authorizationId.value,
userId: params.userId.value,
communityName: params.communityName,
}),
)
return auth
}
// 工厂方法 - 管理员直接授权社区
static createCommunity(params: {
userId: UserId
communityName: string
adminId: AdminUserId
skipAssessment?: boolean
}): AuthorizationRole {
const skipAssessment = params.skipAssessment ?? false
const auth = new AuthorizationRole({
authorizationId: AuthorizationId.generate(),
userId: params.userId,
roleType: RoleType.COMMUNITY,
regionCode: RegionCode.create(params.communityName),
regionName: params.communityName,
status: AuthorizationStatus.AUTHORIZED,
displayTitle: params.communityName,
authorizedAt: new Date(),
authorizedBy: params.adminId,
revokedAt: null,
revokedBy: null,
revokeReason: null,
assessmentConfig: AssessmentConfig.forCommunity(),
requireLocalPercentage: 0,
exemptFromPercentageCheck: true,
benefitActive: skipAssessment,
benefitActivatedAt: skipAssessment ? new Date() : null,
benefitDeactivatedAt: null,
currentMonthIndex: skipAssessment ? 1 : 0,
createdAt: new Date(),
updatedAt: new Date(),
})
auth.addDomainEvent(
new CommunityAuthorizedEvent({
authorizationId: auth.authorizationId.value,
userId: params.userId.value,
communityName: params.communityName,
authorizedBy: params.adminId.value,
}),
)
return auth
}
// 工厂方法 - 创建授权省公司
static createAuthProvinceCompany(params: {
userId: UserId
provinceCode: string
provinceName: string
}): AuthorizationRole {
const auth = new AuthorizationRole({
authorizationId: AuthorizationId.generate(),
userId: params.userId,
roleType: RoleType.AUTH_PROVINCE_COMPANY,
regionCode: RegionCode.create(params.provinceCode),
regionName: params.provinceName,
status: AuthorizationStatus.PENDING,
displayTitle: `授权${params.provinceName}`,
authorizedAt: null,
authorizedBy: null,
revokedAt: null,
revokedBy: null,
revokeReason: null,
assessmentConfig: AssessmentConfig.forAuthProvince(),
requireLocalPercentage: 5.0,
exemptFromPercentageCheck: false,
benefitActive: false,
benefitActivatedAt: null,
benefitDeactivatedAt: null,
currentMonthIndex: 0,
createdAt: new Date(),
updatedAt: new Date(),
})
auth.addDomainEvent(
new AuthProvinceCompanyRequestedEvent({
authorizationId: auth.authorizationId.value,
userId: params.userId.value,
provinceCode: params.provinceCode,
provinceName: params.provinceName,
}),
)
return auth
}
// 工厂方法 - 创建正式省公司
static createProvinceCompany(params: {
userId: UserId
provinceCode: string
provinceName: string
adminId: AdminUserId
skipAssessment?: boolean
}): AuthorizationRole {
const skipAssessment = params.skipAssessment ?? false
const auth = new AuthorizationRole({
authorizationId: AuthorizationId.generate(),
userId: params.userId,
roleType: RoleType.PROVINCE_COMPANY,
regionCode: RegionCode.create(params.provinceCode),
regionName: params.provinceName,
status: AuthorizationStatus.AUTHORIZED,
displayTitle: params.provinceName,
authorizedAt: new Date(),
authorizedBy: params.adminId,
revokedAt: null,
revokedBy: null,
revokeReason: null,
assessmentConfig: AssessmentConfig.forProvince(),
requireLocalPercentage: 0,
exemptFromPercentageCheck: true,
benefitActive: skipAssessment,
benefitActivatedAt: skipAssessment ? new Date() : null,
benefitDeactivatedAt: null,
currentMonthIndex: skipAssessment ? 1 : 0,
createdAt: new Date(),
updatedAt: new Date(),
})
auth.addDomainEvent(
new ProvinceCompanyAuthorizedEvent({
authorizationId: auth.authorizationId.value,
userId: params.userId.value,
provinceCode: params.provinceCode,
provinceName: params.provinceName,
authorizedBy: params.adminId.value,
}),
)
return auth
}
// 工厂方法 - 创建授权市公司
static createAuthCityCompany(params: {
userId: UserId
cityCode: string
cityName: string
}): AuthorizationRole {
const auth = new AuthorizationRole({
authorizationId: AuthorizationId.generate(),
userId: params.userId,
roleType: RoleType.AUTH_CITY_COMPANY,
regionCode: RegionCode.create(params.cityCode),
regionName: params.cityName,
status: AuthorizationStatus.PENDING,
displayTitle: `授权${params.cityName}`,
authorizedAt: null,
authorizedBy: null,
revokedAt: null,
revokedBy: null,
revokeReason: null,
assessmentConfig: AssessmentConfig.forAuthCity(),
requireLocalPercentage: 5.0,
exemptFromPercentageCheck: false,
benefitActive: false,
benefitActivatedAt: null,
benefitDeactivatedAt: null,
currentMonthIndex: 0,
createdAt: new Date(),
updatedAt: new Date(),
})
auth.addDomainEvent(
new AuthCityCompanyRequestedEvent({
authorizationId: auth.authorizationId.value,
userId: params.userId.value,
cityCode: params.cityCode,
cityName: params.cityName,
}),
)
return auth
}
// 工厂方法 - 创建正式市公司
static createCityCompany(params: {
userId: UserId
cityCode: string
cityName: string
adminId: AdminUserId
skipAssessment?: boolean
}): AuthorizationRole {
const skipAssessment = params.skipAssessment ?? false
const auth = new AuthorizationRole({
authorizationId: AuthorizationId.generate(),
userId: params.userId,
roleType: RoleType.CITY_COMPANY,
regionCode: RegionCode.create(params.cityCode),
regionName: params.cityName,
status: AuthorizationStatus.AUTHORIZED,
displayTitle: params.cityName,
authorizedAt: new Date(),
authorizedBy: params.adminId,
revokedAt: null,
revokedBy: null,
revokeReason: null,
assessmentConfig: AssessmentConfig.forCity(),
requireLocalPercentage: 0,
exemptFromPercentageCheck: true,
benefitActive: skipAssessment,
benefitActivatedAt: skipAssessment ? new Date() : null,
benefitDeactivatedAt: null,
currentMonthIndex: skipAssessment ? 1 : 0,
createdAt: new Date(),
updatedAt: new Date(),
})
auth.addDomainEvent(
new CityCompanyAuthorizedEvent({
authorizationId: auth.authorizationId.value,
userId: params.userId.value,
cityCode: params.cityCode,
cityName: params.cityName,
authorizedBy: params.adminId.value,
}),
)
return auth
}
// 工厂方法 - Admin授权省团队
static createAuthProvinceCompanyByAdmin(params: {
userId: UserId
provinceCode: string
provinceName: string
adminId: AdminUserId
skipAssessment?: boolean
}): AuthorizationRole {
const skipAssessment = params.skipAssessment ?? false
const auth = new AuthorizationRole({
authorizationId: AuthorizationId.generate(),
userId: params.userId,
roleType: RoleType.AUTH_PROVINCE_COMPANY,
regionCode: RegionCode.create(params.provinceCode),
regionName: params.provinceName,
status: AuthorizationStatus.AUTHORIZED,
displayTitle: `授权${params.provinceName}`,
authorizedAt: new Date(),
authorizedBy: params.adminId,
revokedAt: null,
revokedBy: null,
revokeReason: null,
assessmentConfig: AssessmentConfig.forAuthProvince(),
requireLocalPercentage: 5.0,
exemptFromPercentageCheck: false,
benefitActive: skipAssessment,
benefitActivatedAt: skipAssessment ? new Date() : null,
benefitDeactivatedAt: null,
currentMonthIndex: skipAssessment ? 1 : 0,
createdAt: new Date(),
updatedAt: new Date(),
})
auth.addDomainEvent(
new AuthProvinceCompanyGrantedEvent({
authorizationId: auth.authorizationId.value,
userId: params.userId.value,
provinceCode: params.provinceCode,
provinceName: params.provinceName,
authorizedBy: params.adminId.value,
}),
)
return auth
}
// 工厂方法 - Admin授权市团队
static createAuthCityCompanyByAdmin(params: {
userId: UserId
cityCode: string
cityName: string
adminId: AdminUserId
skipAssessment?: boolean
}): AuthorizationRole {
const skipAssessment = params.skipAssessment ?? false
const auth = new AuthorizationRole({
authorizationId: AuthorizationId.generate(),
userId: params.userId,
roleType: RoleType.AUTH_CITY_COMPANY,
regionCode: RegionCode.create(params.cityCode),
regionName: params.cityName,
status: AuthorizationStatus.AUTHORIZED,
displayTitle: `授权${params.cityName}`,
authorizedAt: new Date(),
authorizedBy: params.adminId,
revokedAt: null,
revokedBy: null,
revokeReason: null,
assessmentConfig: AssessmentConfig.forAuthCity(),
requireLocalPercentage: 5.0,
exemptFromPercentageCheck: false,
benefitActive: skipAssessment,
benefitActivatedAt: skipAssessment ? new Date() : null,
benefitDeactivatedAt: null,
currentMonthIndex: skipAssessment ? 1 : 0,
createdAt: new Date(),
updatedAt: new Date(),
})
auth.addDomainEvent(
new AuthCityCompanyGrantedEvent({
authorizationId: auth.authorizationId.value,
userId: params.userId.value,
cityCode: params.cityCode,
cityName: params.cityName,
authorizedBy: params.adminId.value,
}),
)
return auth
}
// 核心领域行为
/**
* 激活权益(初始考核达标后)
*/
activateBenefit(): void {
if (this._benefitActive) {
throw new DomainError('权益已激活')
}
this._status = AuthorizationStatus.AUTHORIZED
this._benefitActive = true
this._benefitActivatedAt = new Date()
this._currentMonthIndex = 1
this._updatedAt = new Date()
this.addDomainEvent(
new BenefitActivatedEvent({
authorizationId: this._authorizationId.value,
userId: this._userId.value,
roleType: this._roleType,
regionCode: this._regionCode.value,
}),
)
}
/**
* 失效权益(月度考核不达标)
*/
deactivateBenefit(reason: string): void {
if (!this._benefitActive) {
return
}
this._benefitActive = false
this._benefitDeactivatedAt = new Date()
this._currentMonthIndex = 0 // 重置月份索引
this._updatedAt = new Date()
this.addDomainEvent(
new BenefitDeactivatedEvent({
authorizationId: this._authorizationId.value,
userId: this._userId.value,
roleType: this._roleType,
reason,
}),
)
}
/**
* 管理员授权
*/
authorize(adminId: AdminUserId): void {
if (this._status === AuthorizationStatus.AUTHORIZED) {
throw new DomainError('已授权,无需重复授权')
}
this._status = AuthorizationStatus.AUTHORIZED
this._authorizedAt = new Date()
this._authorizedBy = adminId
this._updatedAt = new Date()
this.addDomainEvent(
new RoleAuthorizedEvent({
authorizationId: this._authorizationId.value,
userId: this._userId.value,
roleType: this._roleType,
regionCode: this._regionCode.value,
authorizedBy: adminId.value,
}),
)
}
/**
* 撤销授权
*/
revoke(adminId: AdminUserId, reason: string): void {
if (this._status === AuthorizationStatus.REVOKED) {
throw new DomainError('已撤销')
}
this._status = AuthorizationStatus.REVOKED
this._revokedAt = new Date()
this._revokedBy = adminId
this._revokeReason = reason
this._benefitActive = false
this._benefitDeactivatedAt = new Date()
this._updatedAt = new Date()
this.addDomainEvent(
new RoleRevokedEvent({
authorizationId: this._authorizationId.value,
userId: this._userId.value,
roleType: this._roleType,
regionCode: this._regionCode.value,
reason,
revokedBy: adminId.value,
}),
)
}
/**
* 豁免占比考核
*/
exemptLocalPercentageCheck(adminId: AdminUserId): void {
this._exemptFromPercentageCheck = true
this._updatedAt = new Date()
this.addDomainEvent(
new PercentageCheckExemptedEvent({
authorizationId: this._authorizationId.value,
userId: this._userId.value,
exemptedBy: adminId.value,
}),
)
}
/**
* 取消豁免占比考核
*/
cancelExemptLocalPercentageCheck(): void {
this._exemptFromPercentageCheck = false
this._updatedAt = new Date()
}
/**
* 递增考核月份
*/
incrementMonthIndex(): void {
this._currentMonthIndex += 1
this._updatedAt = new Date()
}
/**
* 获取初始考核目标
*/
getInitialTarget(): number {
return this._assessmentConfig.initialTargetTreeCount
}
/**
* 检查是否需要占比考核
*/
needsLocalPercentageCheck(): boolean {
return (
!this._exemptFromPercentageCheck &&
this._requireLocalPercentage > 0 &&
(this._roleType === RoleType.AUTH_PROVINCE_COMPANY ||
this._roleType === RoleType.AUTH_CITY_COMPANY)
)
}
/**
* 检查是否需要阶梯考核
*/
needsLadderAssessment(): boolean {
return this._assessmentConfig.monthlyTargetType === MonthlyTargetType.LADDER
}
/**
* 检查是否需要固定月度考核
*/
needsFixedAssessment(): boolean {
return this._assessmentConfig.monthlyTargetType === MonthlyTargetType.FIXED
}
/**
* 转换为持久化数据
*/
toPersistence(): Record<string, any> {
return {
id: this._authorizationId.value,
userId: this._userId.accountSequence,
accountSequence: this._userId.accountSequence,
roleType: this._roleType,
regionCode: this._regionCode.value,
regionName: this._regionName,
status: this._status,
displayTitle: this._displayTitle,
authorizedAt: this._authorizedAt,
authorizedBy: this._authorizedBy?.accountSequence || null,
revokedAt: this._revokedAt,
revokedBy: this._revokedBy?.accountSequence || null,
revokeReason: this._revokeReason,
initialTargetTreeCount: this._assessmentConfig.initialTargetTreeCount,
monthlyTargetType: this._assessmentConfig.monthlyTargetType,
requireLocalPercentage: this._requireLocalPercentage,
exemptFromPercentageCheck: this._exemptFromPercentageCheck,
benefitActive: this._benefitActive,
benefitActivatedAt: this._benefitActivatedAt,
benefitDeactivatedAt: this._benefitDeactivatedAt,
currentMonthIndex: this._currentMonthIndex,
createdAt: this._createdAt,
updatedAt: this._updatedAt,
}
}
}