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:
parent
737fc3bb3c
commit
e4389a5733
|
|
@ -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)`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue