feat(wallet-service): allocateFunds 添加幂等性检查
防止重复分配奖励,通过检查流水表中的 orderId + accountSequence + allocationType 组合 🤖 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
bf7f4af88d
commit
f9e2d8483c
|
|
@ -898,9 +898,26 @@ export class WalletApplicationService {
|
|||
|
||||
let totalAmount = 0;
|
||||
let allocatedCount = 0;
|
||||
let skippedCount = 0;
|
||||
|
||||
for (const allocation of command.allocations) {
|
||||
try {
|
||||
// 幂等性检查:检查该订单+账户+分配类型是否已分配
|
||||
const alreadyAllocated = await this.checkAllocationExists(
|
||||
command.orderId,
|
||||
allocation.targetId,
|
||||
allocation.allocationType,
|
||||
);
|
||||
|
||||
if (alreadyAllocated) {
|
||||
this.logger.warn(
|
||||
`[IDEMPOTENT] Allocation already exists for order ${command.orderId}, ` +
|
||||
`target ${allocation.targetId}, type ${allocation.allocationType}. Skipping.`,
|
||||
);
|
||||
skippedCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (allocation.targetType === 'USER') {
|
||||
// 分配给用户钱包
|
||||
await this.allocateToUserWallet(allocation, command.orderId);
|
||||
|
|
@ -920,16 +937,41 @@ export class WalletApplicationService {
|
|||
}
|
||||
|
||||
this.logger.log(
|
||||
`Allocated ${allocatedCount}/${command.allocations.length} items, total ${totalAmount} USDT`,
|
||||
`Allocated ${allocatedCount}/${command.allocations.length} items (skipped ${skippedCount}), total ${totalAmount} USDT`,
|
||||
);
|
||||
|
||||
return {
|
||||
success: allocatedCount > 0,
|
||||
success: allocatedCount > 0 || skippedCount > 0,
|
||||
allocatedCount,
|
||||
totalAmount,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查分配是否已存在(幂等性检查)
|
||||
* 通过查询流水表判断该订单+账户+分配类型是否已处理
|
||||
*/
|
||||
private async checkAllocationExists(
|
||||
orderId: string,
|
||||
targetId: string,
|
||||
allocationType: string,
|
||||
): Promise<boolean> {
|
||||
// 查询流水表,检查是否已存在该订单的分配记录
|
||||
// 流水的 payloadJson 中存储了 allocationType
|
||||
const existingEntry = await this.prisma.ledgerEntry.findFirst({
|
||||
where: {
|
||||
refOrderId: orderId,
|
||||
accountSequence: targetId,
|
||||
payloadJson: {
|
||||
path: ['allocationType'],
|
||||
equals: allocationType,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return !!existingEntry;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分配资金到用户钱包
|
||||
* 支持用户账户 (D+日期+序号) 和系统账户 (S+序号, 7+省代码, 6+市代码, 9+省代码, 8+市代码)
|
||||
|
|
|
|||
Loading…
Reference in New Issue