rwadurian/backend/services/contribution-service/src/domain/aggregates/contribution-account.aggreg...

598 lines
24 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Decimal from 'decimal.js';
import { ContributionAmount } from '../value-objects/contribution-amount.vo';
/**
* 贡献值来源类型
*/
export enum ContributionSourceType {
PERSONAL = 'PERSONAL', // 来自自己认种
TEAM_LEVEL = 'TEAM_LEVEL', // 来自团队层级 (1-15级)
TEAM_BONUS = 'TEAM_BONUS', // 来自团队加成奖励 (3档)
// ========== 转让相关(纯新增)==========
// 卖方转出(负数金额)
TRANSFER_OUT_PERSONAL = 'TRANSFER_OUT_PERSONAL', // 卖方个人算力转出
TRANSFER_OUT_TEAM_LEVEL = 'TRANSFER_OUT_TEAM_LEVEL', // 卖方上线团队层级算力转出
TRANSFER_OUT_BONUS = 'TRANSFER_OUT_BONUS', // 卖方个人加成算力转出
// 买方转入(正数金额)
TRANSFER_IN_PERSONAL = 'TRANSFER_IN_PERSONAL', // 买方个人算力转入
TRANSFER_IN_TEAM_LEVEL = 'TRANSFER_IN_TEAM_LEVEL', // 买方上线团队层级算力转入
TRANSFER_IN_BONUS = 'TRANSFER_IN_BONUS', // 买方个人加成算力转入
}
/**
* 算力账户聚合根
* 管理用户的贡献值/算力
*
* 设计说明:
* - 个人算力:自己认种,立即生效
* - 层级算力下级1-15层认种的分成每层0.5%共7.5%
* - 加成算力团队加成3档各2.5%共7.5%
*
* 解锁规则:
* - 自己认种解锁层级1-5 + 加成第1档
* - 直推≥2人认种解锁加成第2档
* - 直推≥3人认种解锁层级6-10
* - 直推≥4人认种解锁加成第3档
* - 直推≥5人认种解锁层级11-15
*/
export class ContributionAccountAggregate {
private _id: bigint | null;
private _accountSequence: string;
// ========== 个人算力(立即生效)==========
private _personalContribution: ContributionAmount;
// ========== 15级层级待解锁算力 ==========
private _level1Pending: ContributionAmount;
private _level2Pending: ContributionAmount;
private _level3Pending: ContributionAmount;
private _level4Pending: ContributionAmount;
private _level5Pending: ContributionAmount;
private _level6Pending: ContributionAmount;
private _level7Pending: ContributionAmount;
private _level8Pending: ContributionAmount;
private _level9Pending: ContributionAmount;
private _level10Pending: ContributionAmount;
private _level11Pending: ContributionAmount;
private _level12Pending: ContributionAmount;
private _level13Pending: ContributionAmount;
private _level14Pending: ContributionAmount;
private _level15Pending: ContributionAmount;
// ========== 3档加成待解锁算力 ==========
private _bonusTier1Pending: ContributionAmount;
private _bonusTier2Pending: ContributionAmount;
private _bonusTier3Pending: ContributionAmount;
// ========== 汇总字段 ==========
private _totalLevelPending: ContributionAmount;
private _totalBonusPending: ContributionAmount;
private _totalPending: ContributionAmount;
private _totalUnlocked: ContributionAmount;
private _effectiveContribution: ContributionAmount;
// ========== 解锁条件状态 ==========
private _hasAdopted: boolean;
private _directReferralAdoptedCount: number;
private _unlockedLevelDepth: number; // 0, 5, 10, 15
private _unlockedBonusTiers: number; // 0, 1, 2, 3
private _version: number;
private _createdAt: Date;
private _updatedAt: Date;
constructor(props: {
id?: bigint | null;
accountSequence: string;
personalContribution?: ContributionAmount;
level1Pending?: ContributionAmount;
level2Pending?: ContributionAmount;
level3Pending?: ContributionAmount;
level4Pending?: ContributionAmount;
level5Pending?: ContributionAmount;
level6Pending?: ContributionAmount;
level7Pending?: ContributionAmount;
level8Pending?: ContributionAmount;
level9Pending?: ContributionAmount;
level10Pending?: ContributionAmount;
level11Pending?: ContributionAmount;
level12Pending?: ContributionAmount;
level13Pending?: ContributionAmount;
level14Pending?: ContributionAmount;
level15Pending?: ContributionAmount;
bonusTier1Pending?: ContributionAmount;
bonusTier2Pending?: ContributionAmount;
bonusTier3Pending?: ContributionAmount;
totalLevelPending?: ContributionAmount;
totalBonusPending?: ContributionAmount;
totalPending?: ContributionAmount;
totalUnlocked?: ContributionAmount;
effectiveContribution?: ContributionAmount;
hasAdopted?: boolean;
directReferralAdoptedCount?: number;
unlockedLevelDepth?: number;
unlockedBonusTiers?: number;
version?: number;
createdAt?: Date;
updatedAt?: Date;
}) {
this._id = props.id ?? null;
this._accountSequence = props.accountSequence;
this._personalContribution = props.personalContribution ?? ContributionAmount.zero();
// 15级待解锁
this._level1Pending = props.level1Pending ?? ContributionAmount.zero();
this._level2Pending = props.level2Pending ?? ContributionAmount.zero();
this._level3Pending = props.level3Pending ?? ContributionAmount.zero();
this._level4Pending = props.level4Pending ?? ContributionAmount.zero();
this._level5Pending = props.level5Pending ?? ContributionAmount.zero();
this._level6Pending = props.level6Pending ?? ContributionAmount.zero();
this._level7Pending = props.level7Pending ?? ContributionAmount.zero();
this._level8Pending = props.level8Pending ?? ContributionAmount.zero();
this._level9Pending = props.level9Pending ?? ContributionAmount.zero();
this._level10Pending = props.level10Pending ?? ContributionAmount.zero();
this._level11Pending = props.level11Pending ?? ContributionAmount.zero();
this._level12Pending = props.level12Pending ?? ContributionAmount.zero();
this._level13Pending = props.level13Pending ?? ContributionAmount.zero();
this._level14Pending = props.level14Pending ?? ContributionAmount.zero();
this._level15Pending = props.level15Pending ?? ContributionAmount.zero();
// 3档加成待解锁
this._bonusTier1Pending = props.bonusTier1Pending ?? ContributionAmount.zero();
this._bonusTier2Pending = props.bonusTier2Pending ?? ContributionAmount.zero();
this._bonusTier3Pending = props.bonusTier3Pending ?? ContributionAmount.zero();
// 汇总字段
this._totalLevelPending = props.totalLevelPending ?? ContributionAmount.zero();
this._totalBonusPending = props.totalBonusPending ?? ContributionAmount.zero();
this._totalPending = props.totalPending ?? ContributionAmount.zero();
this._totalUnlocked = props.totalUnlocked ?? ContributionAmount.zero();
this._effectiveContribution = props.effectiveContribution ?? ContributionAmount.zero();
this._hasAdopted = props.hasAdopted ?? false;
this._directReferralAdoptedCount = props.directReferralAdoptedCount ?? 0;
this._unlockedLevelDepth = props.unlockedLevelDepth ?? 0;
this._unlockedBonusTiers = props.unlockedBonusTiers ?? 0;
this._version = props.version ?? 1;
this._createdAt = props.createdAt ?? new Date();
this._updatedAt = props.updatedAt ?? new Date();
}
// Getters
get id(): bigint | null { return this._id; }
get accountSequence(): string { return this._accountSequence; }
get personalContribution(): ContributionAmount { return this._personalContribution; }
// 15级待解锁
get level1Pending(): ContributionAmount { return this._level1Pending; }
get level2Pending(): ContributionAmount { return this._level2Pending; }
get level3Pending(): ContributionAmount { return this._level3Pending; }
get level4Pending(): ContributionAmount { return this._level4Pending; }
get level5Pending(): ContributionAmount { return this._level5Pending; }
get level6Pending(): ContributionAmount { return this._level6Pending; }
get level7Pending(): ContributionAmount { return this._level7Pending; }
get level8Pending(): ContributionAmount { return this._level8Pending; }
get level9Pending(): ContributionAmount { return this._level9Pending; }
get level10Pending(): ContributionAmount { return this._level10Pending; }
get level11Pending(): ContributionAmount { return this._level11Pending; }
get level12Pending(): ContributionAmount { return this._level12Pending; }
get level13Pending(): ContributionAmount { return this._level13Pending; }
get level14Pending(): ContributionAmount { return this._level14Pending; }
get level15Pending(): ContributionAmount { return this._level15Pending; }
// 3档加成待解锁
get bonusTier1Pending(): ContributionAmount { return this._bonusTier1Pending; }
get bonusTier2Pending(): ContributionAmount { return this._bonusTier2Pending; }
get bonusTier3Pending(): ContributionAmount { return this._bonusTier3Pending; }
// 汇总
get totalLevelPending(): ContributionAmount { return this._totalLevelPending; }
get totalBonusPending(): ContributionAmount { return this._totalBonusPending; }
get totalPending(): ContributionAmount { return this._totalPending; }
get totalUnlocked(): ContributionAmount { return this._totalUnlocked; }
get effectiveContribution(): ContributionAmount { return this._effectiveContribution; }
get hasAdopted(): boolean { return this._hasAdopted; }
get directReferralAdoptedCount(): number { return this._directReferralAdoptedCount; }
get unlockedLevelDepth(): number { return this._unlockedLevelDepth; }
get unlockedBonusTiers(): number { return this._unlockedBonusTiers; }
get version(): number { return this._version; }
get createdAt(): Date { return this._createdAt; }
get updatedAt(): Date { return this._updatedAt; }
/**
* 添加个人贡献值(立即生效)
*/
addPersonalContribution(amount: ContributionAmount): void {
this._personalContribution = this._personalContribution.add(amount);
this._effectiveContribution = this._effectiveContribution.add(amount);
this._updatedAt = new Date();
}
/**
* 添加层级待解锁贡献值
* @param levelDepth 层级深度 1-15
* @param amount 贡献值金额
*/
addLevelPendingContribution(levelDepth: number, amount: ContributionAmount): void {
if (levelDepth < 1 || levelDepth > 15) {
throw new Error(`Invalid level depth: ${levelDepth}, must be 1-15`);
}
const levelPendingMap: Record<number, ContributionAmount> = {
1: this._level1Pending,
2: this._level2Pending,
3: this._level3Pending,
4: this._level4Pending,
5: this._level5Pending,
6: this._level6Pending,
7: this._level7Pending,
8: this._level8Pending,
9: this._level9Pending,
10: this._level10Pending,
11: this._level11Pending,
12: this._level12Pending,
13: this._level13Pending,
14: this._level14Pending,
15: this._level15Pending,
};
// 更新对应层级的待解锁金额
switch (levelDepth) {
case 1: this._level1Pending = this._level1Pending.add(amount); break;
case 2: this._level2Pending = this._level2Pending.add(amount); break;
case 3: this._level3Pending = this._level3Pending.add(amount); break;
case 4: this._level4Pending = this._level4Pending.add(amount); break;
case 5: this._level5Pending = this._level5Pending.add(amount); break;
case 6: this._level6Pending = this._level6Pending.add(amount); break;
case 7: this._level7Pending = this._level7Pending.add(amount); break;
case 8: this._level8Pending = this._level8Pending.add(amount); break;
case 9: this._level9Pending = this._level9Pending.add(amount); break;
case 10: this._level10Pending = this._level10Pending.add(amount); break;
case 11: this._level11Pending = this._level11Pending.add(amount); break;
case 12: this._level12Pending = this._level12Pending.add(amount); break;
case 13: this._level13Pending = this._level13Pending.add(amount); break;
case 14: this._level14Pending = this._level14Pending.add(amount); break;
case 15: this._level15Pending = this._level15Pending.add(amount); break;
}
this._totalLevelPending = this._totalLevelPending.add(amount);
this._totalPending = this._totalPending.add(amount);
this._updatedAt = new Date();
}
/**
* 添加加成待解锁贡献值
* @param tier 加成档位 1-3
* @param amount 贡献值金额
*/
addBonusTierPendingContribution(tier: number, amount: ContributionAmount): void {
if (tier < 1 || tier > 3) {
throw new Error(`Invalid bonus tier: ${tier}, must be 1-3`);
}
switch (tier) {
case 1: this._bonusTier1Pending = this._bonusTier1Pending.add(amount); break;
case 2: this._bonusTier2Pending = this._bonusTier2Pending.add(amount); break;
case 3: this._bonusTier3Pending = this._bonusTier3Pending.add(amount); break;
}
this._totalBonusPending = this._totalBonusPending.add(amount);
this._totalPending = this._totalPending.add(amount);
this._updatedAt = new Date();
}
/**
* 标记用户已认种
* 解锁层级1-5和加成第1档
*/
markAsAdopted(): void {
if (this._hasAdopted) return; // 已经认种过
this._hasAdopted = true;
this._unlockedLevelDepth = 5; // 解锁1-5级
this._unlockedBonusTiers = 1; // 解锁第1档
this._updatedAt = new Date();
}
/**
* 增加直推认种用户数
*/
incrementDirectReferralAdoptedCount(): void {
this._directReferralAdoptedCount++;
this.updateUnlockStatus();
}
/**
* 设置直推认种用户数
*/
setDirectReferralAdoptedCount(count: number): void {
this._directReferralAdoptedCount = count;
this.updateUnlockStatus();
}
/**
* 更新解锁状态
* 根据直推认种用户数
*/
private updateUnlockStatus(): void {
// 层级解锁规则(只有在已认种的情况下才会解锁)
if (this._hasAdopted) {
if (this._directReferralAdoptedCount >= 5) {
this._unlockedLevelDepth = 15; // 解锁11-15级
} else if (this._directReferralAdoptedCount >= 3) {
this._unlockedLevelDepth = 10; // 解锁6-10级
} else {
this._unlockedLevelDepth = 5; // 保持1-5级
}
}
// 加成解锁规则
let bonusTiers = 0;
if (this._hasAdopted) bonusTiers = 1; // 自己认种解锁第1档
if (this._directReferralAdoptedCount >= 2) bonusTiers = 2; // 直推≥2解锁第2档
if (this._directReferralAdoptedCount >= 4) bonusTiers = 3; // 直推≥4解锁第3档
this._unlockedBonusTiers = bonusTiers;
this._updatedAt = new Date();
}
/**
* 解锁待解锁的贡献值
* 根据当前解锁深度,将对应的 pending 转移到 unlocked
* @returns 本次解锁的金额
*/
unlockPendingContributions(): ContributionAmount {
let unlockAmount = ContributionAmount.zero();
// 解锁层级算力
if (this._unlockedLevelDepth >= 5) {
unlockAmount = unlockAmount.add(this._level1Pending);
unlockAmount = unlockAmount.add(this._level2Pending);
unlockAmount = unlockAmount.add(this._level3Pending);
unlockAmount = unlockAmount.add(this._level4Pending);
unlockAmount = unlockAmount.add(this._level5Pending);
this._level1Pending = ContributionAmount.zero();
this._level2Pending = ContributionAmount.zero();
this._level3Pending = ContributionAmount.zero();
this._level4Pending = ContributionAmount.zero();
this._level5Pending = ContributionAmount.zero();
}
if (this._unlockedLevelDepth >= 10) {
unlockAmount = unlockAmount.add(this._level6Pending);
unlockAmount = unlockAmount.add(this._level7Pending);
unlockAmount = unlockAmount.add(this._level8Pending);
unlockAmount = unlockAmount.add(this._level9Pending);
unlockAmount = unlockAmount.add(this._level10Pending);
this._level6Pending = ContributionAmount.zero();
this._level7Pending = ContributionAmount.zero();
this._level8Pending = ContributionAmount.zero();
this._level9Pending = ContributionAmount.zero();
this._level10Pending = ContributionAmount.zero();
}
if (this._unlockedLevelDepth >= 15) {
unlockAmount = unlockAmount.add(this._level11Pending);
unlockAmount = unlockAmount.add(this._level12Pending);
unlockAmount = unlockAmount.add(this._level13Pending);
unlockAmount = unlockAmount.add(this._level14Pending);
unlockAmount = unlockAmount.add(this._level15Pending);
this._level11Pending = ContributionAmount.zero();
this._level12Pending = ContributionAmount.zero();
this._level13Pending = ContributionAmount.zero();
this._level14Pending = ContributionAmount.zero();
this._level15Pending = ContributionAmount.zero();
}
// 解锁加成算力
if (this._unlockedBonusTiers >= 1) {
unlockAmount = unlockAmount.add(this._bonusTier1Pending);
this._bonusTier1Pending = ContributionAmount.zero();
}
if (this._unlockedBonusTiers >= 2) {
unlockAmount = unlockAmount.add(this._bonusTier2Pending);
this._bonusTier2Pending = ContributionAmount.zero();
}
if (this._unlockedBonusTiers >= 3) {
unlockAmount = unlockAmount.add(this._bonusTier3Pending);
this._bonusTier3Pending = ContributionAmount.zero();
}
// 更新汇总
this._totalUnlocked = this._totalUnlocked.add(unlockAmount);
this._totalPending = this._totalPending.subtract(unlockAmount);
this._effectiveContribution = this._effectiveContribution.add(unlockAmount);
this.recalculatePendingTotals();
this._updatedAt = new Date();
return unlockAmount;
}
/**
* 重新计算待解锁汇总
*/
private recalculatePendingTotals(): void {
this._totalLevelPending = this._level1Pending
.add(this._level2Pending)
.add(this._level3Pending)
.add(this._level4Pending)
.add(this._level5Pending)
.add(this._level6Pending)
.add(this._level7Pending)
.add(this._level8Pending)
.add(this._level9Pending)
.add(this._level10Pending)
.add(this._level11Pending)
.add(this._level12Pending)
.add(this._level13Pending)
.add(this._level14Pending)
.add(this._level15Pending);
this._totalBonusPending = this._bonusTier1Pending
.add(this._bonusTier2Pending)
.add(this._bonusTier3Pending);
this._totalPending = this._totalLevelPending.add(this._totalBonusPending);
}
/**
* 增加版本号(乐观锁)
*/
incrementVersion(): void {
this._version++;
this._updatedAt = new Date();
}
/**
* 创建新账户
*/
static create(accountSequence: string): ContributionAccountAggregate {
return new ContributionAccountAggregate({ accountSequence });
}
/**
* 从持久化数据恢复
*/
static fromPersistence(data: {
id: bigint;
accountSequence: string;
personalContribution: Decimal;
level1Pending: Decimal;
level2Pending: Decimal;
level3Pending: Decimal;
level4Pending: Decimal;
level5Pending: Decimal;
level6Pending: Decimal;
level7Pending: Decimal;
level8Pending: Decimal;
level9Pending: Decimal;
level10Pending: Decimal;
level11Pending: Decimal;
level12Pending: Decimal;
level13Pending: Decimal;
level14Pending: Decimal;
level15Pending: Decimal;
bonusTier1Pending: Decimal;
bonusTier2Pending: Decimal;
bonusTier3Pending: Decimal;
totalLevelPending: Decimal;
totalBonusPending: Decimal;
totalPending: Decimal;
totalUnlocked: Decimal;
effectiveContribution: Decimal;
hasAdopted: boolean;
directReferralAdoptedCount: number;
unlockedLevelDepth: number;
unlockedBonusTiers: number;
version: number;
createdAt: Date;
updatedAt: Date;
}): ContributionAccountAggregate {
return new ContributionAccountAggregate({
id: data.id,
accountSequence: data.accountSequence,
personalContribution: new ContributionAmount(data.personalContribution),
level1Pending: new ContributionAmount(data.level1Pending),
level2Pending: new ContributionAmount(data.level2Pending),
level3Pending: new ContributionAmount(data.level3Pending),
level4Pending: new ContributionAmount(data.level4Pending),
level5Pending: new ContributionAmount(data.level5Pending),
level6Pending: new ContributionAmount(data.level6Pending),
level7Pending: new ContributionAmount(data.level7Pending),
level8Pending: new ContributionAmount(data.level8Pending),
level9Pending: new ContributionAmount(data.level9Pending),
level10Pending: new ContributionAmount(data.level10Pending),
level11Pending: new ContributionAmount(data.level11Pending),
level12Pending: new ContributionAmount(data.level12Pending),
level13Pending: new ContributionAmount(data.level13Pending),
level14Pending: new ContributionAmount(data.level14Pending),
level15Pending: new ContributionAmount(data.level15Pending),
bonusTier1Pending: new ContributionAmount(data.bonusTier1Pending),
bonusTier2Pending: new ContributionAmount(data.bonusTier2Pending),
bonusTier3Pending: new ContributionAmount(data.bonusTier3Pending),
totalLevelPending: new ContributionAmount(data.totalLevelPending),
totalBonusPending: new ContributionAmount(data.totalBonusPending),
totalPending: new ContributionAmount(data.totalPending),
totalUnlocked: new ContributionAmount(data.totalUnlocked),
effectiveContribution: new ContributionAmount(data.effectiveContribution),
hasAdopted: data.hasAdopted,
directReferralAdoptedCount: data.directReferralAdoptedCount,
unlockedLevelDepth: data.unlockedLevelDepth,
unlockedBonusTiers: data.unlockedBonusTiers,
version: data.version,
createdAt: data.createdAt,
updatedAt: data.updatedAt,
});
}
/**
* 转换为持久化数据
*/
toPersistence(): {
accountSequence: string;
personalContribution: Decimal;
level1Pending: Decimal;
level2Pending: Decimal;
level3Pending: Decimal;
level4Pending: Decimal;
level5Pending: Decimal;
level6Pending: Decimal;
level7Pending: Decimal;
level8Pending: Decimal;
level9Pending: Decimal;
level10Pending: Decimal;
level11Pending: Decimal;
level12Pending: Decimal;
level13Pending: Decimal;
level14Pending: Decimal;
level15Pending: Decimal;
bonusTier1Pending: Decimal;
bonusTier2Pending: Decimal;
bonusTier3Pending: Decimal;
totalLevelPending: Decimal;
totalBonusPending: Decimal;
totalPending: Decimal;
totalUnlocked: Decimal;
effectiveContribution: Decimal;
hasAdopted: boolean;
directReferralAdoptedCount: number;
unlockedLevelDepth: number;
unlockedBonusTiers: number;
version: number;
} {
return {
accountSequence: this._accountSequence,
personalContribution: this._personalContribution.value,
level1Pending: this._level1Pending.value,
level2Pending: this._level2Pending.value,
level3Pending: this._level3Pending.value,
level4Pending: this._level4Pending.value,
level5Pending: this._level5Pending.value,
level6Pending: this._level6Pending.value,
level7Pending: this._level7Pending.value,
level8Pending: this._level8Pending.value,
level9Pending: this._level9Pending.value,
level10Pending: this._level10Pending.value,
level11Pending: this._level11Pending.value,
level12Pending: this._level12Pending.value,
level13Pending: this._level13Pending.value,
level14Pending: this._level14Pending.value,
level15Pending: this._level15Pending.value,
bonusTier1Pending: this._bonusTier1Pending.value,
bonusTier2Pending: this._bonusTier2Pending.value,
bonusTier3Pending: this._bonusTier3Pending.value,
totalLevelPending: this._totalLevelPending.value,
totalBonusPending: this._totalBonusPending.value,
totalPending: this._totalPending.value,
totalUnlocked: this._totalUnlocked.value,
effectiveContribution: this._effectiveContribution.value,
hasAdopted: this._hasAdopted,
directReferralAdoptedCount: this._directReferralAdoptedCount,
unlockedLevelDepth: this._unlockedLevelDepth,
unlockedBonusTiers: this._unlockedBonusTiers,
version: this._version,
};
}
}