fix(wallet-service): 修复流水查询使用 userId 导致记录丢失的问题
将所有流水查询从 userId 改为使用 accountSequence: - getMyLedger: 使用 findByAccountSequence 替代 findByUserId - getLedgerStatistics: 查询改为按 accountSequence - getLedgerTrend: 查询改为按 accountSequence - findByAccountSequence: 添加 HIDDEN_ENTRY_TYPES 过滤 🤖 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
53df97839d
commit
217be89c43
|
|
@ -22,7 +22,7 @@ export class LedgerController {
|
||||||
@Query() queryDto: GetMyLedgerQueryDTO,
|
@Query() queryDto: GetMyLedgerQueryDTO,
|
||||||
): Promise<PaginatedLedgerResponseDTO> {
|
): Promise<PaginatedLedgerResponseDTO> {
|
||||||
const query = new GetMyLedgerQuery(
|
const query = new GetMyLedgerQuery(
|
||||||
user.userId,
|
user.accountSequence, // 使用 accountSequence 替代 userId
|
||||||
queryDto.page,
|
queryDto.page,
|
||||||
queryDto.pageSize,
|
queryDto.pageSize,
|
||||||
queryDto.entryType,
|
queryDto.entryType,
|
||||||
|
|
@ -39,7 +39,7 @@ export class LedgerController {
|
||||||
async getStatistics(
|
async getStatistics(
|
||||||
@CurrentUser() user: CurrentUserPayload,
|
@CurrentUser() user: CurrentUserPayload,
|
||||||
): Promise<LedgerStatisticsResponseDTO> {
|
): Promise<LedgerStatisticsResponseDTO> {
|
||||||
return this.walletService.getLedgerStatistics(user.userId);
|
return this.walletService.getLedgerStatistics(user.accountSequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('trend')
|
@Get('trend')
|
||||||
|
|
@ -51,6 +51,6 @@ export class LedgerController {
|
||||||
@Query('days') days?: string,
|
@Query('days') days?: string,
|
||||||
): Promise<LedgerTrendResponseDTO> {
|
): Promise<LedgerTrendResponseDTO> {
|
||||||
const numDays = days ? parseInt(days, 10) : 30;
|
const numDays = days ? parseInt(days, 10) : 30;
|
||||||
return this.walletService.getLedgerTrend(user.userId, numDays);
|
return this.walletService.getLedgerTrend(user.accountSequence, numDays);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { LedgerEntryType, AssetType } from '@/domain/value-objects';
|
||||||
|
|
||||||
export class GetMyLedgerQuery {
|
export class GetMyLedgerQuery {
|
||||||
constructor(
|
constructor(
|
||||||
public readonly userId: string,
|
public readonly accountSequence: string, // 使用 accountSequence 替代 userId
|
||||||
public readonly page?: number,
|
public readonly page?: number,
|
||||||
public readonly pageSize?: number,
|
public readonly pageSize?: number,
|
||||||
public readonly entryType?: LedgerEntryType,
|
public readonly entryType?: LedgerEntryType,
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ describe('WalletApplicationService', () => {
|
||||||
const createMockWallet = (userId: bigint, usdtBalance = 0) => {
|
const createMockWallet = (userId: bigint, usdtBalance = 0) => {
|
||||||
return WalletAccount.reconstruct({
|
return WalletAccount.reconstruct({
|
||||||
walletId: BigInt(1),
|
walletId: BigInt(1),
|
||||||
accountSequence: userId, // 使用 userId 作为 accountSequence
|
accountSequence: `D${userId.toString().padStart(11, '0')}`, // 生成 accountSequence
|
||||||
userId,
|
userId,
|
||||||
usdtAvailable: new Decimal(usdtBalance),
|
usdtAvailable: new Decimal(usdtBalance),
|
||||||
usdtFrozen: new Decimal(0),
|
usdtFrozen: new Decimal(0),
|
||||||
|
|
@ -51,6 +51,8 @@ describe('WalletApplicationService', () => {
|
||||||
expiredTotalUsdt: new Decimal(0),
|
expiredTotalUsdt: new Decimal(0),
|
||||||
expiredTotalHashpower: new Decimal(0),
|
expiredTotalHashpower: new Decimal(0),
|
||||||
status: 'ACTIVE',
|
status: 'ACTIVE',
|
||||||
|
hasPlanted: false,
|
||||||
|
version: 0,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
});
|
});
|
||||||
|
|
@ -69,6 +71,7 @@ describe('WalletApplicationService', () => {
|
||||||
save: jest.fn(),
|
save: jest.fn(),
|
||||||
saveAll: jest.fn(),
|
saveAll: jest.fn(),
|
||||||
findByUserId: jest.fn(),
|
findByUserId: jest.fn(),
|
||||||
|
findByAccountSequence: jest.fn(),
|
||||||
findByRefOrderId: jest.fn(),
|
findByRefOrderId: jest.fn(),
|
||||||
findByRefTxHash: jest.fn(),
|
findByRefTxHash: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
@ -187,9 +190,9 @@ describe('WalletApplicationService', () => {
|
||||||
|
|
||||||
describe('getMyLedger', () => {
|
describe('getMyLedger', () => {
|
||||||
it('should return paginated ledger entries', async () => {
|
it('should return paginated ledger entries', async () => {
|
||||||
const query = new GetMyLedgerQuery('1', 1, 10);
|
const query = new GetMyLedgerQuery('D00000000001', 1, 10);
|
||||||
|
|
||||||
mockLedgerRepo.findByUserId.mockResolvedValue({
|
mockLedgerRepo.findByAccountSequence.mockResolvedValue({
|
||||||
data: [],
|
data: [],
|
||||||
total: 0,
|
total: 0,
|
||||||
page: 1,
|
page: 1,
|
||||||
|
|
|
||||||
|
|
@ -1916,10 +1916,9 @@ export class WalletApplicationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getMyLedger(query: GetMyLedgerQuery): Promise<PaginatedLedgerDTO> {
|
async getMyLedger(query: GetMyLedgerQuery): Promise<PaginatedLedgerDTO> {
|
||||||
const userId = BigInt(query.userId);
|
// 使用 accountSequence 查询流水(废弃 userId 查询)
|
||||||
|
const result = await this.ledgerRepo.findByAccountSequence(
|
||||||
const result = await this.ledgerRepo.findByUserId(
|
query.accountSequence,
|
||||||
userId,
|
|
||||||
{
|
{
|
||||||
entryType: query.entryType,
|
entryType: query.entryType,
|
||||||
assetType: query.assetType,
|
assetType: query.assetType,
|
||||||
|
|
@ -1934,7 +1933,7 @@ export class WalletApplicationService {
|
||||||
|
|
||||||
// 调试日志:打印流水数据(只打印前5条)
|
// 调试日志:打印流水数据(只打印前5条)
|
||||||
this.logger.debug(`[getMyLedger] ======== 流水数据调试 ========`);
|
this.logger.debug(`[getMyLedger] ======== 流水数据调试 ========`);
|
||||||
this.logger.debug(`[getMyLedger] userId: ${userId}, 共 ${result.data.length} 条, 总计 ${result.total} 条`);
|
this.logger.debug(`[getMyLedger] accountSequence: ${query.accountSequence}, 共 ${result.data.length} 条, 总计 ${result.total} 条`);
|
||||||
for (let i = 0; i < result.data.length && i < 5; i++) {
|
for (let i = 0; i < result.data.length && i < 5; i++) {
|
||||||
const entry = result.data[i];
|
const entry = result.data[i];
|
||||||
const allocationType = (entry.payloadJson as Record<string, unknown>)?.allocationType;
|
const allocationType = (entry.payloadJson as Record<string, unknown>)?.allocationType;
|
||||||
|
|
@ -2458,7 +2457,7 @@ export class WalletApplicationService {
|
||||||
/**
|
/**
|
||||||
* 获取流水统计信息
|
* 获取流水统计信息
|
||||||
*/
|
*/
|
||||||
async getLedgerStatistics(userId: string): Promise<{
|
async getLedgerStatistics(accountSequence: string): Promise<{
|
||||||
totalIncome: number;
|
totalIncome: number;
|
||||||
totalExpense: number;
|
totalExpense: number;
|
||||||
netAmount: number;
|
netAmount: number;
|
||||||
|
|
@ -2472,11 +2471,9 @@ export class WalletApplicationService {
|
||||||
startDate: string;
|
startDate: string;
|
||||||
endDate: string;
|
endDate: string;
|
||||||
}> {
|
}> {
|
||||||
const userIdBigInt = BigInt(userId);
|
// 使用 accountSequence 查询流水(废弃 userId 查询)
|
||||||
|
|
||||||
// 获取所有流水
|
|
||||||
const entries = await this.prisma.ledgerEntry.findMany({
|
const entries = await this.prisma.ledgerEntry.findMany({
|
||||||
where: { userId: userIdBigInt, assetType: 'USDT' },
|
where: { accountSequence, assetType: 'USDT' },
|
||||||
orderBy: { createdAt: 'asc' },
|
orderBy: { createdAt: 'asc' },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -2547,7 +2544,7 @@ export class WalletApplicationService {
|
||||||
/**
|
/**
|
||||||
* 获取流水趋势
|
* 获取流水趋势
|
||||||
*/
|
*/
|
||||||
async getLedgerTrend(userId: string, days: number = 30): Promise<{
|
async getLedgerTrend(accountSequence: string, days: number = 30): Promise<{
|
||||||
dailyTrend: Array<{
|
dailyTrend: Array<{
|
||||||
date: string;
|
date: string;
|
||||||
income: number;
|
income: number;
|
||||||
|
|
@ -2560,14 +2557,14 @@ export class WalletApplicationService {
|
||||||
periodExpense: number;
|
periodExpense: number;
|
||||||
periodNet: number;
|
periodNet: number;
|
||||||
}> {
|
}> {
|
||||||
const userIdBigInt = BigInt(userId);
|
// 使用 accountSequence 查询流水(废弃 userId 查询)
|
||||||
const startDate = new Date();
|
const startDate = new Date();
|
||||||
startDate.setDate(startDate.getDate() - days);
|
startDate.setDate(startDate.getDate() - days);
|
||||||
startDate.setHours(0, 0, 0, 0);
|
startDate.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
const entries = await this.prisma.ledgerEntry.findMany({
|
const entries = await this.prisma.ledgerEntry.findMany({
|
||||||
where: {
|
where: {
|
||||||
userId: userIdBigInt,
|
accountSequence,
|
||||||
assetType: 'USDT',
|
assetType: 'USDT',
|
||||||
createdAt: { gte: startDate },
|
createdAt: { gte: startDate },
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ describe('WalletAccount Aggregate', () => {
|
||||||
let wallet: WalletAccount;
|
let wallet: WalletAccount;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
wallet = WalletAccount.createNew(BigInt(1), UserId.create(1));
|
wallet = WalletAccount.createNew('D00000000001', UserId.create(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('createNew', () => {
|
describe('createNew', () => {
|
||||||
|
|
|
||||||
|
|
@ -133,9 +133,14 @@ export class LedgerEntryRepositoryImpl implements ILedgerEntryRepository {
|
||||||
filters?: LedgerFilters,
|
filters?: LedgerFilters,
|
||||||
pagination?: Pagination,
|
pagination?: Pagination,
|
||||||
): Promise<PaginatedResult<LedgerEntry>> {
|
): Promise<PaginatedResult<LedgerEntry>> {
|
||||||
const where: Record<string, unknown> = { accountSequence };
|
const where: Record<string, unknown> = {
|
||||||
|
accountSequence,
|
||||||
|
// 排除临时性流水类型
|
||||||
|
entryType: { notIn: LedgerEntryRepositoryImpl.HIDDEN_ENTRY_TYPES },
|
||||||
|
};
|
||||||
|
|
||||||
if (filters?.entryType) {
|
if (filters?.entryType) {
|
||||||
|
// 如果用户指定了类型筛选,则使用用户指定的类型
|
||||||
where.entryType = filters.entryType;
|
where.entryType = filters.entryType;
|
||||||
}
|
}
|
||||||
if (filters?.assetType) {
|
if (filters?.assetType) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue