fix(pre-planting): 修复预种权益资金分配字段名错误(allocationType 丢失)
原 executeAllocations 使用了错误的 FundAllocationItem 字段名: - targetAccountId → 应为 targetId - 缺少 allocationType 字段 - targetType 错误地使用了 rightType 值而非 'USER'|'SYSTEM' 导致所有预种订单的 SHARE_RIGHT/COMMUNITY_RIGHT 等权益分配静默失败, 资金未能分配到推荐人/社区/省市账户,同时流水明细中也不显示预种记录。 修复内容: 1. WalletServiceClient 新增 allocatePrePlantingFunds 方法(使用正确格式) 2. executeAllocations 改用新方法,正确设置 targetType/targetId/allocationType 3. InternalPrePlantingController 新增 POST /admin/retry-rewards 历史数据修复端点 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
62bbbca609
commit
1d0e4352df
|
|
@ -357,6 +357,55 @@ export class WalletServiceClient {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预种资金分配(使用与 reward-service 一致的 FundAllocationItem 格式)
|
||||
*
|
||||
* 与现有 allocateFunds 的区别:
|
||||
* - targetType: 'USER' | 'SYSTEM'(而非 FundAllocationTargetType 枚举)
|
||||
* - targetId: 账户序列号(而非 targetAccountId)
|
||||
* - allocationType: 权益类型字符串(用于 wallet-service ledger 分类)
|
||||
*
|
||||
* 规则:账户序列号以 S 开头 → SYSTEM,否则 → USER
|
||||
*/
|
||||
async allocatePrePlantingFunds(request: {
|
||||
orderId: string;
|
||||
allocations: Array<{
|
||||
targetType: 'USER' | 'SYSTEM';
|
||||
targetId: string;
|
||||
allocationType: string;
|
||||
amount: number;
|
||||
metadata?: Record<string, unknown>;
|
||||
}>;
|
||||
}): Promise<boolean> {
|
||||
try {
|
||||
return await this.withRetry(
|
||||
`allocatePrePlantingFunds(${request.orderId})`,
|
||||
async () => {
|
||||
const response = await firstValueFrom(
|
||||
this.httpService.post(
|
||||
`${this.baseUrl}/api/v1/wallets/allocate-funds`,
|
||||
request,
|
||||
),
|
||||
);
|
||||
// wallet-service 使用 TransformInterceptor,响应格式为
|
||||
// { success: true, data: { success: bool, allocatedCount: N, ... }, timestamp: "..." }
|
||||
const data = response.data?.data ?? response.data;
|
||||
return data?.success === true;
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to allocate pre-planting funds for order: ${request.orderId}`,
|
||||
error,
|
||||
);
|
||||
if (this.configService.get('NODE_ENV') === 'development') {
|
||||
this.logger.warn('Development mode: simulating successful pre-planting allocation');
|
||||
return true;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入底池
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Param,
|
||||
Query,
|
||||
HttpStatus,
|
||||
|
|
@ -15,6 +16,7 @@ import {
|
|||
} from '@nestjs/swagger';
|
||||
import { PrePlantingApplicationService } from '../../application/services/pre-planting-application.service';
|
||||
import { PrismaService } from '../../../infrastructure/persistence/prisma/prisma.service';
|
||||
import { WalletServiceClient } from '../../../infrastructure/external/wallet-service.client';
|
||||
|
||||
@ApiTags('预种计划-内部API')
|
||||
@Controller('internal/pre-planting')
|
||||
|
|
@ -24,6 +26,7 @@ export class InternalPrePlantingController {
|
|||
constructor(
|
||||
private readonly prePlantingService: PrePlantingApplicationService,
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly walletClient: WalletServiceClient,
|
||||
) {}
|
||||
|
||||
@Get('eligibility/:accountSequence')
|
||||
|
|
@ -234,4 +237,69 @@ export class InternalPrePlantingController {
|
|||
pendingContracts,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* [2026-02-28] 历史数据修复:重新执行预种权益资金分配
|
||||
*
|
||||
* 背景:原 executeAllocations 使用了错误的 FundAllocationItem 字段名(targetAccountId→targetId)
|
||||
* 导致所有预种订单的权益分配(SHARE_RIGHT/COMMUNITY_RIGHT 等)静默失败。
|
||||
*
|
||||
* 本接口读取 pre_planting_reward_entries 表中已持久化的分配记录,
|
||||
* 逐笔重新调用 wallet-service /allocate-funds(wallet-service 内置幂等检查,不会重复入账)。
|
||||
*/
|
||||
@Post('admin/retry-rewards')
|
||||
@ApiOperation({ summary: '重新执行预种权益资金分配(历史数据修复)' })
|
||||
@ApiResponse({ status: HttpStatus.OK, description: '修复结果' })
|
||||
async retryRewards() {
|
||||
this.logger.log('[PRE-PLANTING RETRY] Starting rewards retry for all historical orders...');
|
||||
|
||||
// 1. 查询所有有 SETTLED 分配记录的订单号
|
||||
const distinctOrders = await this.prisma.prePlantingRewardEntry.findMany({
|
||||
where: { rewardStatus: 'SETTLED' },
|
||||
select: { sourceOrderNo: true },
|
||||
distinct: ['sourceOrderNo'],
|
||||
});
|
||||
|
||||
const orderNos = distinctOrders.map((r) => r.sourceOrderNo);
|
||||
this.logger.log(`[PRE-PLANTING RETRY] Found ${orderNos.length} orders to retry`);
|
||||
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
const failedOrders: string[] = [];
|
||||
|
||||
// 2. 逐笔订单重新调用 wallet-service allocate-funds
|
||||
for (const orderNo of orderNos) {
|
||||
try {
|
||||
const entries = await this.prisma.prePlantingRewardEntry.findMany({
|
||||
where: { sourceOrderNo: orderNo, rewardStatus: 'SETTLED' },
|
||||
});
|
||||
|
||||
if (entries.length === 0) continue;
|
||||
|
||||
await this.walletClient.allocatePrePlantingFunds({
|
||||
orderId: orderNo,
|
||||
allocations: entries.map((e) => ({
|
||||
targetType: e.recipientAccountSequence.startsWith('S') ? 'SYSTEM' : 'USER',
|
||||
targetId: e.recipientAccountSequence,
|
||||
allocationType: e.rightType,
|
||||
amount: Number(e.usdtAmount),
|
||||
})),
|
||||
});
|
||||
|
||||
successCount++;
|
||||
this.logger.log(`[PRE-PLANTING RETRY] OK: ${orderNo} (${entries.length} entries)`);
|
||||
} catch (err) {
|
||||
failCount++;
|
||||
failedOrders.push(orderNo);
|
||||
this.logger.error(`[PRE-PLANTING RETRY] FAILED: ${orderNo}`, err);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
total: orderNos.length,
|
||||
success: successCount,
|
||||
failed: failCount,
|
||||
failedOrders,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,6 +86,11 @@ export class PrePlantingRewardService {
|
|||
|
||||
/**
|
||||
* Step 5: 事务提交后执行资金转账(HTTP 调用 wallet-service)
|
||||
*
|
||||
* [2026-02-28] 修复:使用正确的 FundAllocationItem 格式
|
||||
* - targetType: 'USER' | 'SYSTEM'(账户序列以 S 开头 → SYSTEM,否则 → USER)
|
||||
* - targetId: 账户序列号(原错误字段名 targetAccountId 已修正)
|
||||
* - allocationType: 权益类型字符串(用于 wallet-service ledger 分类)
|
||||
*/
|
||||
async executeAllocations(
|
||||
orderNo: string,
|
||||
|
|
@ -96,12 +101,14 @@ export class PrePlantingRewardService {
|
|||
(a) => a.rewardStatus === PrePlantingRewardStatus.SETTLED,
|
||||
);
|
||||
|
||||
await this.walletClient.allocateFunds({
|
||||
await this.walletClient.allocatePrePlantingFunds({
|
||||
orderId: orderNo,
|
||||
allocations: settledAllocations.map((a) => ({
|
||||
targetType: a.rightType as unknown as import('../../../domain/value-objects/fund-allocation-target-type.enum').FundAllocationTargetType,
|
||||
// 账户序列以 S 开头 → 系统账户 SYSTEM,其余(D/9/8/7/6 开头)→ 用户账户 USER
|
||||
targetType: a.recipientAccountSequence.startsWith('S') ? 'SYSTEM' : 'USER',
|
||||
targetId: a.recipientAccountSequence,
|
||||
allocationType: a.rightType,
|
||||
amount: a.amount,
|
||||
targetAccountId: a.recipientAccountSequence,
|
||||
})),
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue