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 totalAmount = 0;
|
||||||
let allocatedCount = 0;
|
let allocatedCount = 0;
|
||||||
|
let skippedCount = 0;
|
||||||
|
|
||||||
for (const allocation of command.allocations) {
|
for (const allocation of command.allocations) {
|
||||||
try {
|
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') {
|
if (allocation.targetType === 'USER') {
|
||||||
// 分配给用户钱包
|
// 分配给用户钱包
|
||||||
await this.allocateToUserWallet(allocation, command.orderId);
|
await this.allocateToUserWallet(allocation, command.orderId);
|
||||||
|
|
@ -920,16 +937,41 @@ export class WalletApplicationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.log(
|
this.logger.log(
|
||||||
`Allocated ${allocatedCount}/${command.allocations.length} items, total ${totalAmount} USDT`,
|
`Allocated ${allocatedCount}/${command.allocations.length} items (skipped ${skippedCount}), total ${totalAmount} USDT`,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: allocatedCount > 0,
|
success: allocatedCount > 0 || skippedCount > 0,
|
||||||
allocatedCount,
|
allocatedCount,
|
||||||
totalAmount,
|
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+市代码)
|
* 支持用户账户 (D+日期+序号) 和系统账户 (S+序号, 7+省代码, 6+市代码, 9+省代码, 8+市代码)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue