fix(wallet-service): 优化资金分配逻辑 - 区分直接到账和待领取

- SHARE_RIGHT (分享权益): 写入 pending_rewards 表,24小时待领取
- PROVINCE_TEAM_RIGHT/PROVINCE_AREA_RIGHT/CITY_TEAM_RIGHT/CITY_AREA_RIGHT: 直接到账
- COMMUNITY_RIGHT (社区权益): 进入总部社区账户 S0000000001,直接到账

🤖 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-13 04:51:34 -08:00
parent 737fc3bb3c
commit e4389a5733
1 changed files with 115 additions and 27 deletions

View File

@ -619,41 +619,40 @@ export class WalletApplicationService {
*
* (D++) (S+, 7+, 6+, 9+, 8+)
*
* 使 pending_rewards
*
* - SHARE_RIGHT (): pending_rewards 24
* - PROVINCE_TEAM_RIGHT, PROVINCE_AREA_RIGHT, CITY_TEAM_RIGHT, CITY_AREA_RIGHT: 直接到账
* - COMMUNITY_RIGHT (): S0000000001
*/
private async allocateToUserWallet(
allocation: FundAllocationItem,
orderId: string,
): Promise<void> {
// targetId 是 accountSequence
// - 用户账户: D2512120001
// - 固定系统账户: S0000000001 (userId: -1 to -100, 由migration seed创建)
// - 省团队账户: 7440000 (7 + provinceCode, userId = 7440000)
// - 市团队账户: 6440100 (6 + cityCode, userId = 6440100)
// - 省区域账户: 9440000 (9 + provinceCode, userId = 9440000)
// - 市区域账户: 8440100 (8 + cityCode, userId = 8440100)
const amount = Money.USDT(allocation.amount);
const allocationType = allocation.allocationType;
// 为系统账户生成 userId (用于数据库约束)
let systemUserId = BigInt(0);
const targetId = allocation.targetId;
if (targetId.startsWith('9') || targetId.startsWith('8') || targetId.startsWith('7') || targetId.startsWith('6')) {
// 区域/团队账户: 9440000, 8440100, 7440000, 6440100 -> userId = accountSequence
systemUserId = BigInt(targetId);
} else if (targetId.startsWith('S')) {
// 固定系统账户: S0000000001 -> userId = -1 (负数由seed创建直接查找)
const numPart = targetId.slice(1);
systemUserId = BigInt(-parseInt(numPart, 10));
}
// 使用 getOrCreate 自动创建不存在的账户(仅用于区域/团队账户的动态创建)
// 固定系统账户(S开头)应该已由migration seed创建
const wallet = await this.walletRepo.getOrCreate(targetId, systemUserId);
if (!wallet) {
this.logger.warn(`Failed to get or create wallet for accountSequence ${allocation.targetId}`);
// 社区权益直接进入总部社区账户 S0000000001
if (allocationType === 'COMMUNITY_RIGHT') {
await this.allocateToHeadquartersCommunity(allocation, orderId);
return;
}
const amount = Money.USDT(allocation.amount);
// 省市团队/区域权益直接到账
if (['PROVINCE_TEAM_RIGHT', 'PROVINCE_AREA_RIGHT', 'CITY_TEAM_RIGHT', 'CITY_AREA_RIGHT'].includes(allocationType)) {
await this.allocateToRegionAccount(allocation, orderId);
return;
}
// 分享权益 (SHARE_RIGHT) - 写入 pending_rewards 表待领取
// targetId 是 accountSequence (用户账户: D2512120001)
const targetId = allocation.targetId;
// 用户账户 D 开头userId 从 targetId 解析不出来,需要查询
const wallet = await this.walletRepo.findByAccountSequence(targetId);
if (!wallet) {
this.logger.warn(`Failed to find wallet for accountSequence ${targetId}`);
return;
}
// 添加待领取奖励24小时后过期- 写入 pending_rewards 表
const expireAt = new Date(Date.now() + 24 * 60 * 60 * 1000);
@ -688,7 +687,96 @@ export class WalletApplicationService {
await this.walletCacheService.invalidateWallet(wallet.userId.value);
this.logger.debug(
`Allocated ${allocation.amount} USDT to user ${allocation.targetId} for ${allocation.allocationType}`,
`Allocated ${allocation.amount} USDT to user ${allocation.targetId} for ${allocation.allocationType} (pending)`,
);
}
/**
* S0000000001
*/
private async allocateToHeadquartersCommunity(
allocation: FundAllocationItem,
orderId: string,
): Promise<void> {
const headquartersAccountSequence = 'S0000000001';
const wallet = await this.walletRepo.findByAccountSequence(headquartersAccountSequence);
if (!wallet) {
this.logger.error(`Headquarters community account not found: ${headquartersAccountSequence}`);
return;
}
const amount = Money.USDT(allocation.amount);
wallet.addAvailableBalance(amount);
await this.walletRepo.save(wallet);
// 记录流水
const ledgerEntry = LedgerEntry.create({
accountSequence: wallet.accountSequence,
userId: wallet.userId,
entryType: LedgerEntryType.SYSTEM_ALLOCATION,
amount,
refOrderId: orderId,
memo: `${allocation.allocationType} - headquarters community allocation`,
payloadJson: {
allocationType: allocation.allocationType,
metadata: allocation.metadata,
},
});
await this.ledgerRepo.save(ledgerEntry);
await this.walletCacheService.invalidateWallet(wallet.userId.value);
this.logger.debug(
`Allocated ${allocation.amount} USDT to headquarters community ${headquartersAccountSequence} for ${allocation.allocationType}`,
);
}
/**
* /
* - 省团队账户: 7+provinceCode (e.g., 7440000)
* - 市团队账户: 6+cityCode (e.g., 6440100)
* - 省区域账户: 9+provinceCode (e.g., 9440000)
* - 市区域账户: 8+cityCode (e.g., 8440100)
*/
private async allocateToRegionAccount(
allocation: FundAllocationItem,
orderId: string,
): Promise<void> {
const targetId = allocation.targetId;
// 生成 userId (用于数据库约束) - userId = accountSequence 数值
const systemUserId = BigInt(targetId);
// 使用 getOrCreate 自动创建不存在的账户
const wallet = await this.walletRepo.getOrCreate(targetId, systemUserId);
if (!wallet) {
this.logger.warn(`Failed to get or create wallet for region account ${targetId}`);
return;
}
const amount = Money.USDT(allocation.amount);
wallet.addAvailableBalance(amount);
await this.walletRepo.save(wallet);
// 记录流水
const ledgerEntry = LedgerEntry.create({
accountSequence: wallet.accountSequence,
userId: wallet.userId,
entryType: LedgerEntryType.SYSTEM_ALLOCATION,
amount,
refOrderId: orderId,
memo: `${allocation.allocationType} - region account allocation`,
payloadJson: {
allocationType: allocation.allocationType,
metadata: allocation.metadata,
},
});
await this.ledgerRepo.save(ledgerEntry);
await this.walletCacheService.invalidateWallet(wallet.userId.value);
this.logger.debug(
`Allocated ${allocation.amount} USDT to region account ${targetId} for ${allocation.allocationType} (direct)`,
);
}