fix: 修复 wallet-service 支持 accountSequence 格式及订单状态机

1. wallet-service/internal-wallet.controller.ts:
   - getBalance: 支持 accountSequence (D开头) 和 userId (纯数字) 两种格式

2. wallet-service/wallet-application.service.ts:
   - freezeForPlanting: 修复 BigInt 转换错误,优先按 accountSequence 查找钱包
   - confirmPlantingDeduction: 同上
   - unfreezeForPlanting: 同上
   - getMyWallet: 支持 userId='0' 的情况(仅通过 accountSequence 查询)

3. planting-service/planting-order.aggregate.ts:
   - schedulePoolInjection: 状态检查从 FUND_ALLOCATED 改为 PAID
   - 原因: 资金分配已移至 reward-service 异步处理

修复问题: "Cannot convert D25121300006 to a BigInt"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2025-12-12 22:35:18 -08:00
parent ad82e3ee44
commit d20ff9e9b5
3 changed files with 50 additions and 31 deletions

View File

@ -262,9 +262,10 @@ export class PlantingOrder {
/** /**
* *
* reward-service
*/ */
schedulePoolInjection(batchId: bigint, scheduledTime: Date): void { schedulePoolInjection(batchId: bigint, scheduledTime: Date): void {
this.ensureStatus(PlantingOrderStatus.FUND_ALLOCATED); this.ensureStatus(PlantingOrderStatus.PAID);
this._poolInjectionBatchId = batchId; this._poolInjectionBatchId = batchId;
this._poolInjectionScheduledTime = scheduledTime; this._poolInjectionScheduledTime = scheduledTime;

View File

@ -29,8 +29,14 @@ export class InternalWalletController {
@ApiParam({ name: 'userId', description: '用户ID或accountSequence' }) @ApiParam({ name: 'userId', description: '用户ID或accountSequence' })
@ApiResponse({ status: 200, description: '余额信息' }) @ApiResponse({ status: 200, description: '余额信息' })
async getBalance(@Param('userId') userId: string) { async getBalance(@Param('userId') userId: string) {
// 优先使用 accountSequence如果相同则使用 userId // 判断是 accountSequence (以 D 开头) 还是 userId (纯数字)
const query = new GetMyWalletQuery(userId, userId); const isAccountSequence = userId.startsWith('D');
// 如果是 accountSequenceuserId 参数设为 '0'(会被忽略,通过 accountSequence 查找)
// 如果是纯 userIdaccountSequence 参数设为 userId会通过 userId 查找)
const query = new GetMyWalletQuery(
isAccountSequence ? userId : userId, // accountSequence
isAccountSequence ? '0' : userId, // userId (如果是 accountSequence 则忽略)
);
const wallet = await this.walletService.getMyWallet(query); const wallet = await this.walletService.getMyWallet(query);
return { return {
userId, userId,

View File

@ -196,7 +196,6 @@ export class WalletApplicationService {
this.logger.log(`[freezeForPlanting] amount: ${command.amount}`); this.logger.log(`[freezeForPlanting] amount: ${command.amount}`);
this.logger.log(`[freezeForPlanting] orderId: ${command.orderId}`); this.logger.log(`[freezeForPlanting] orderId: ${command.orderId}`);
const userId = BigInt(command.userId);
const amount = Money.USDT(command.amount); const amount = Money.USDT(command.amount);
this.logger.log(`[freezeForPlanting] 解析后 amount.value: ${amount.value}`); this.logger.log(`[freezeForPlanting] 解析后 amount.value: ${amount.value}`);
@ -216,7 +215,11 @@ export class WalletApplicationService {
// 优先按 accountSequence 查找,如果未找到则按 userId 查找 // 优先按 accountSequence 查找,如果未找到则按 userId 查找
let wallet = await this.walletRepo.findByAccountSequence(command.userId); let wallet = await this.walletRepo.findByAccountSequence(command.userId);
if (!wallet) { if (!wallet) {
wallet = await this.walletRepo.findByUserId(userId); // 尝试将 userId 转换为 BigInt如果不是 accountSequence 格式)
const isAccountSequence = command.userId.startsWith('D');
if (!isAccountSequence) {
wallet = await this.walletRepo.findByUserId(BigInt(command.userId));
}
} }
if (!wallet) { if (!wallet) {
this.logger.error(`[freezeForPlanting] 钱包不存在: userId/accountSequence=${command.userId}`); this.logger.error(`[freezeForPlanting] 钱包不存在: userId/accountSequence=${command.userId}`);
@ -249,7 +252,7 @@ export class WalletApplicationService {
// 记录冻结流水 // 记录冻结流水
const ledgerEntry = LedgerEntry.create({ const ledgerEntry = LedgerEntry.create({
accountSequence: wallet.accountSequence, accountSequence: wallet.accountSequence,
userId: UserId.create(userId), userId: wallet.userId,
entryType: LedgerEntryType.PLANT_FREEZE, entryType: LedgerEntryType.PLANT_FREEZE,
amount: Money.signed(-command.amount, 'USDT'), // Negative: 可用余额减少 amount: Money.signed(-command.amount, 'USDT'), // Negative: 可用余额减少
balanceAfter: wallet.balances.usdt.available, balanceAfter: wallet.balances.usdt.available,
@ -259,7 +262,7 @@ export class WalletApplicationService {
await this.ledgerRepo.save(ledgerEntry); await this.ledgerRepo.save(ledgerEntry);
this.logger.log(`[freezeForPlanting] 流水已记录`); this.logger.log(`[freezeForPlanting] 流水已记录`);
await this.walletCacheService.invalidateWallet(userId); await this.walletCacheService.invalidateWallet(wallet.userId.value);
this.logger.log(`[freezeForPlanting] 成功冻结 ${command.amount} USDT for order ${command.orderId}`); this.logger.log(`[freezeForPlanting] 成功冻结 ${command.amount} USDT for order ${command.orderId}`);
return { success: true, frozenAmount: command.amount }; return { success: true, frozenAmount: command.amount };
@ -270,8 +273,6 @@ export class WalletApplicationService {
* *
*/ */
async confirmPlantingDeduction(command: ConfirmPlantingDeductionCommand): Promise<boolean> { async confirmPlantingDeduction(command: ConfirmPlantingDeductionCommand): Promise<boolean> {
const userId = BigInt(command.userId);
// 查找冻结记录,获取冻结金额 // 查找冻结记录,获取冻结金额
const existingEntries = await this.ledgerRepo.findByRefOrderId(command.orderId); const existingEntries = await this.ledgerRepo.findByRefOrderId(command.orderId);
@ -300,7 +301,11 @@ export class WalletApplicationService {
// 优先按 accountSequence 查找,如果未找到则按 userId 查找 // 优先按 accountSequence 查找,如果未找到则按 userId 查找
let wallet = await this.walletRepo.findByAccountSequence(command.userId); let wallet = await this.walletRepo.findByAccountSequence(command.userId);
if (!wallet) { if (!wallet) {
wallet = await this.walletRepo.findByUserId(userId); // 尝试将 userId 转换为 BigInt如果不是 accountSequence 格式)
const isAccountSequence = command.userId.startsWith('D');
if (!isAccountSequence) {
wallet = await this.walletRepo.findByUserId(BigInt(command.userId));
}
} }
if (!wallet) { if (!wallet) {
throw new WalletNotFoundError(`userId/accountSequence: ${command.userId}`); throw new WalletNotFoundError(`userId/accountSequence: ${command.userId}`);
@ -313,7 +318,7 @@ export class WalletApplicationService {
// 记录扣款流水 // 记录扣款流水
const ledgerEntry = LedgerEntry.create({ const ledgerEntry = LedgerEntry.create({
accountSequence: wallet.accountSequence, accountSequence: wallet.accountSequence,
userId: UserId.create(userId), userId: wallet.userId,
entryType: LedgerEntryType.PLANT_PAYMENT, entryType: LedgerEntryType.PLANT_PAYMENT,
amount: Money.signed(-frozenAmount.value, 'USDT'), amount: Money.signed(-frozenAmount.value, 'USDT'),
balanceAfter: wallet.balances.usdt.available, balanceAfter: wallet.balances.usdt.available,
@ -322,7 +327,7 @@ export class WalletApplicationService {
}); });
await this.ledgerRepo.save(ledgerEntry); await this.ledgerRepo.save(ledgerEntry);
await this.walletCacheService.invalidateWallet(userId); await this.walletCacheService.invalidateWallet(wallet.userId.value);
this.logger.log(`Confirmed deduction ${frozenAmount.value} USDT for order ${command.orderId}`); this.logger.log(`Confirmed deduction ${frozenAmount.value} USDT for order ${command.orderId}`);
return true; return true;
@ -333,8 +338,6 @@ export class WalletApplicationService {
* *
*/ */
async unfreezeForPlanting(command: UnfreezeForPlantingCommand): Promise<boolean> { async unfreezeForPlanting(command: UnfreezeForPlantingCommand): Promise<boolean> {
const userId = BigInt(command.userId);
// 查找相关流水 // 查找相关流水
const existingEntries = await this.ledgerRepo.findByRefOrderId(command.orderId); const existingEntries = await this.ledgerRepo.findByRefOrderId(command.orderId);
@ -378,7 +381,11 @@ export class WalletApplicationService {
// 优先按 accountSequence 查找,如果未找到则按 userId 查找 // 优先按 accountSequence 查找,如果未找到则按 userId 查找
let wallet = await this.walletRepo.findByAccountSequence(command.userId); let wallet = await this.walletRepo.findByAccountSequence(command.userId);
if (!wallet) { if (!wallet) {
wallet = await this.walletRepo.findByUserId(userId); // 尝试将 userId 转换为 BigInt如果不是 accountSequence 格式)
const isAccountSequence = command.userId.startsWith('D');
if (!isAccountSequence) {
wallet = await this.walletRepo.findByUserId(BigInt(command.userId));
}
} }
if (!wallet) { if (!wallet) {
throw new WalletNotFoundError(`userId/accountSequence: ${command.userId}`); throw new WalletNotFoundError(`userId/accountSequence: ${command.userId}`);
@ -391,7 +398,7 @@ export class WalletApplicationService {
// 记录解冻流水 // 记录解冻流水
const ledgerEntry = LedgerEntry.create({ const ledgerEntry = LedgerEntry.create({
accountSequence: wallet.accountSequence, accountSequence: wallet.accountSequence,
userId: UserId.create(userId), userId: wallet.userId,
entryType: LedgerEntryType.PLANT_UNFREEZE, entryType: LedgerEntryType.PLANT_UNFREEZE,
amount: frozenAmount, // Positive: 可用余额增加 amount: frozenAmount, // Positive: 可用余额增加
balanceAfter: wallet.balances.usdt.available, balanceAfter: wallet.balances.usdt.available,
@ -400,7 +407,7 @@ export class WalletApplicationService {
}); });
await this.ledgerRepo.save(ledgerEntry); await this.ledgerRepo.save(ledgerEntry);
await this.walletCacheService.invalidateWallet(userId); await this.walletCacheService.invalidateWallet(wallet.userId.value);
this.logger.log(`Unfrozen ${frozenAmount.value} USDT for order ${command.orderId}`); this.logger.log(`Unfrozen ${frozenAmount.value} USDT for order ${command.orderId}`);
return true; return true;
@ -915,23 +922,28 @@ export class WalletApplicationService {
async getMyWallet(query: GetMyWalletQuery): Promise<WalletDTO> { async getMyWallet(query: GetMyWalletQuery): Promise<WalletDTO> {
const accountSequence = query.accountSequence; const accountSequence = query.accountSequence;
const userId = BigInt(query.userId); // userId 可能是 '0' (当仅通过 accountSequence 查询时),此时跳过缓存和 BigInt 转换
const userIdStr = query.userId;
const hasValidUserId = userIdStr && userIdStr !== '0' && !userIdStr.startsWith('D');
const userId = hasValidUserId ? BigInt(userIdStr) : BigInt(0);
// Try to get from cache first // Try to get from cache first (only if we have a valid userId)
const cached = await this.walletCacheService.getWallet(userId); if (hasValidUserId) {
if (cached) { const cached = await this.walletCacheService.getWallet(userId);
this.logger.debug(`Returning cached wallet for user: ${userId}`); if (cached) {
return { this.logger.debug(`Returning cached wallet for user: ${userId}`);
walletId: cached.walletId, return {
userId: cached.userId, walletId: cached.walletId,
balances: cached.balances, userId: cached.userId,
hashpower: cached.hashpower, balances: cached.balances,
rewards: cached.rewards, hashpower: cached.hashpower,
status: cached.status, rewards: cached.rewards,
}; status: cached.status,
};
}
} }
// Cache miss - fetch from database (by accountSequence) // Cache miss or no valid userId - fetch from database (by accountSequence)
const wallet = await this.walletRepo.getOrCreate(accountSequence, userId); const wallet = await this.walletRepo.getOrCreate(accountSequence, userId);
const walletDTO: WalletDTO = { const walletDTO: WalletDTO = {