fix(pre-planting): 预种权益分配metadata与正常认种对齐 + 删除retry-rewards
1. executeAllocations() metadata 修复:
- 原:仅传 { source: 'PRE_PLANTING' },wallet流水缺失所有业务信息
- 现:传完整 metadata(rightType, sourceOrderNo, sourceAccountSequence,
treeCount, provinceCode, cityCode, memo),与正常认种 reward-service 一致
- wallet-service 的 prePlantingPrefix() 通过 metadata.source 添加[预种]前缀
2. SHARE_RIGHT PENDING 机制说明(无代码变更):
- 预种侧只确定收款人,全部标记 SETTLED 发给 wallet-service
- wallet-service.allocateToUserWallet() 内部根据收款方 hasPlanted 判断:
已种→SETTLEABLE / 未种→PENDING(24h过期归总部)
- 与正常认种走同一套 wallet-service 代码
3. 删除无用的 retry-rewards 端点及其 WalletServiceClient 依赖
不涉及历史数据修改,不影响正常认种流程。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d9c238702e
commit
19fca05a81
|
|
@ -16,7 +16,6 @@ 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')
|
||||
|
|
@ -26,7 +25,6 @@ export class InternalPrePlantingController {
|
|||
constructor(
|
||||
private readonly prePlantingService: PrePlantingApplicationService,
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly walletClient: WalletServiceClient,
|
||||
) {}
|
||||
|
||||
@Get('eligibility/:accountSequence')
|
||||
|
|
@ -238,69 +236,4 @@ export class InternalPrePlantingController {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* [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),
|
||||
metadata: { source: 'PRE_PLANTING' },
|
||||
})),
|
||||
});
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -174,7 +174,14 @@ export class PrePlantingApplicationService {
|
|||
orderId: orderNo,
|
||||
});
|
||||
|
||||
await this.rewardService.executeAllocations(orderNo, rewardAllocations);
|
||||
await this.rewardService.executeAllocations(
|
||||
orderNo,
|
||||
rewardAllocations,
|
||||
accountSequence,
|
||||
portionCount,
|
||||
provinceCode,
|
||||
cityCode,
|
||||
);
|
||||
} catch (error) {
|
||||
// 事务失败,解冻余额
|
||||
this.logger.error(
|
||||
|
|
|
|||
|
|
@ -87,16 +87,27 @@ export class PrePlantingRewardService {
|
|||
/**
|
||||
* Step 5: 事务提交后执行资金转账(HTTP 调用 wallet-service)
|
||||
*
|
||||
* [2026-02-28] 修复:使用正确的 FundAllocationItem 格式
|
||||
* - targetType: 'USER' | 'SYSTEM'(账户序列以 S 开头 → SYSTEM,否则 → USER)
|
||||
* - targetId: 账户序列号(原错误字段名 targetAccountId 已修正)
|
||||
* - allocationType: 权益类型字符串(用于 wallet-service ledger 分类)
|
||||
* [2026-02-28] 修复:与正常认种对齐
|
||||
* - 使用正确的 FundAllocationItem 格式(targetType/targetId/allocationType)
|
||||
* - metadata 包含完整信息(rightType, sourceOrderNo, sourceAccountSequence,
|
||||
* treeCount, provinceCode, cityCode, memo),与正常认种 reward-service 一致
|
||||
* - metadata.source = 'PRE_PLANTING' 供 wallet-service 添加 [预种] 前缀
|
||||
*
|
||||
* SHARE_RIGHT 的 PENDING/SETTLEABLE 判断:
|
||||
* 预种侧不做 hasPlanted 判断,全部作为 SETTLED 发送给 wallet-service。
|
||||
* wallet-service.allocateToUserWallet() 内部会查询收款方钱包的 hasPlanted 字段:
|
||||
* - hasPlanted=true → 直接 SETTLEABLE(进可结算余额)
|
||||
* - hasPlanted=false → 创建 pending_rewards(24h 过期归总部 S0000000001)
|
||||
* 这与正常认种的链路完全一致(reward-service → wallet-service 的同一段代码)。
|
||||
*/
|
||||
async executeAllocations(
|
||||
orderNo: string,
|
||||
allocations: RewardAllocation[],
|
||||
sourceAccountSequence: string,
|
||||
treeCount: number,
|
||||
provinceCode: string,
|
||||
cityCode: string,
|
||||
): Promise<void> {
|
||||
// 只转 SETTLED 状态的分配
|
||||
const settledAllocations = allocations.filter(
|
||||
(a) => a.rewardStatus === PrePlantingRewardStatus.SETTLED,
|
||||
);
|
||||
|
|
@ -104,13 +115,20 @@ export class PrePlantingRewardService {
|
|||
await this.walletClient.allocatePrePlantingFunds({
|
||||
orderId: orderNo,
|
||||
allocations: settledAllocations.map((a) => ({
|
||||
// 账户序列以 S 开头 → 系统账户 SYSTEM,其余(D/9/8/7/6 开头)→ 用户账户 USER
|
||||
targetType: a.recipientAccountSequence.startsWith('S') ? 'SYSTEM' : 'USER',
|
||||
targetId: a.recipientAccountSequence,
|
||||
allocationType: a.rightType,
|
||||
amount: a.amount,
|
||||
// source 标识供 wallet-service 在流水备注中加"[预种]"前缀,与普通认种权益区分
|
||||
metadata: { source: 'PRE_PLANTING' },
|
||||
metadata: {
|
||||
source: 'PRE_PLANTING',
|
||||
rightType: a.rightType,
|
||||
sourceOrderNo: orderNo,
|
||||
sourceAccountSequence,
|
||||
treeCount,
|
||||
provinceCode,
|
||||
cityCode,
|
||||
memo: a.memo,
|
||||
},
|
||||
})),
|
||||
});
|
||||
|
||||
|
|
@ -185,7 +203,11 @@ export class PrePlantingRewardService {
|
|||
]);
|
||||
|
||||
// 推荐奖励 (SHARE_RIGHT)
|
||||
// 与现有认种一致:推荐奖励立即发放到推荐人钱包,无论推荐人是否已认种
|
||||
// 预种侧只确定收款人(推荐人 or S0000000005),全部标记 SETTLED 发给 wallet-service。
|
||||
// wallet-service.allocateToUserWallet() 会根据收款方 hasPlanted 自动决定:
|
||||
// 已种 → SETTLEABLE(立即可结算)
|
||||
// 未种 → PENDING(24h,过期归总部 S0000000001)
|
||||
// 与正常认种走同一套 wallet-service 代码,无需预种侧额外判断。
|
||||
const referrer = referralInfo.directReferrer;
|
||||
if (referrer) {
|
||||
allocations.push({
|
||||
|
|
|
|||
Loading…
Reference in New Issue