diff --git a/src/subdomains/generic/support/dto/transaction-list-query.dto.ts b/src/subdomains/generic/support/dto/transaction-list-query.dto.ts new file mode 100644 index 0000000000..2cec934e8a --- /dev/null +++ b/src/subdomains/generic/support/dto/transaction-list-query.dto.ts @@ -0,0 +1,19 @@ +import { IsDateString, IsOptional } from 'class-validator'; + +export class TransactionListQuery { + @IsOptional() + @IsDateString() + createdFrom?: string; + + @IsOptional() + @IsDateString() + createdTo?: string; + + @IsOptional() + @IsDateString() + outputFrom?: string; + + @IsOptional() + @IsDateString() + outputTo?: string; +} diff --git a/src/subdomains/generic/support/dto/user-data-support.dto.ts b/src/subdomains/generic/support/dto/user-data-support.dto.ts index d464ba0b78..da128aaf01 100644 --- a/src/subdomains/generic/support/dto/user-data-support.dto.ts +++ b/src/subdomains/generic/support/dto/user-data-support.dto.ts @@ -80,6 +80,20 @@ export class SellSupportInfo { volume: number; } +export class TransactionListEntry { + id: number; + type?: string; + accountId?: number; + name?: string; + domicile?: string; + created?: Date; + eventDate?: Date; + outputDate?: Date; + assets?: string; + amountInChf?: number; + highRisk?: boolean; +} + export class KycFileListEntry { kycFileId: number; id: number; diff --git a/src/subdomains/generic/support/support.controller.ts b/src/subdomains/generic/support/support.controller.ts index 3e4e77b326..28eb262d01 100644 --- a/src/subdomains/generic/support/support.controller.ts +++ b/src/subdomains/generic/support/support.controller.ts @@ -16,9 +16,11 @@ import { UserActiveGuard } from 'src/shared/auth/user-active.guard'; import { UserRole } from 'src/shared/auth/user-role.enum'; import { RefundDataDto } from 'src/subdomains/core/history/dto/refund-data.dto'; import { BankRefundDto } from 'src/subdomains/core/history/dto/transaction-refund.dto'; +import { TransactionListQuery } from './dto/transaction-list-query.dto'; import { KycFileListEntry, KycFileYearlyStats, + TransactionListEntry, UserDataSupportInfoDetails, UserDataSupportInfoResult, UserDataSupportQuery, @@ -53,6 +55,14 @@ export class SupportController { return this.supportService.getKycFileStats(); } + @Get('transactionList') + @ApiBearerAuth() + @ApiExcludeEndpoint() + @UseGuards(AuthGuard(), RoleGuard(UserRole.COMPLIANCE), UserActiveGuard()) + async getTransactionList(@Query() query: TransactionListQuery): Promise { + return this.supportService.getTransactionList(query); + } + @Get(':id') @ApiBearerAuth() @ApiExcludeEndpoint() diff --git a/src/subdomains/generic/support/support.service.ts b/src/subdomains/generic/support/support.service.ts index cef410deea..7bbef4dd2a 100644 --- a/src/subdomains/generic/support/support.service.ts +++ b/src/subdomains/generic/support/support.service.ts @@ -35,6 +35,7 @@ import { UserData } from '../user/models/user-data/user-data.entity'; import { UserDataService } from '../user/models/user-data/user-data.service'; import { User } from '../user/models/user/user.entity'; import { UserService } from '../user/models/user/user.service'; +import { TransactionListQuery } from './dto/transaction-list-query.dto'; import { BankDataSupportInfo, BankTxSupportInfo, @@ -44,6 +45,7 @@ import { KycFileYearlyStats, KycStepSupportInfo, SellSupportInfo, + TransactionListEntry, TransactionSupportInfo, UserDataSupportInfo, UserDataSupportInfoDetails, @@ -152,8 +154,37 @@ export class SupportService { return result; } + async getTransactionList(query: TransactionListQuery): Promise { + const dateFrom = new Date(query.createdFrom ?? new Date(Date.now() - 3 * 24 * 60 * 60 * 1000).toISOString()); + const dateTo = new Date(query.createdTo ?? new Date().toISOString()); + dateTo.setHours(23, 59, 59, 999); + + const outputFrom = query.outputFrom ? new Date(query.outputFrom) : undefined; + const outputTo = query.outputTo ? new Date(query.outputTo) : undefined; + if (outputTo) outputTo.setHours(23, 59, 59, 999); + + const transactions = await this.transactionService.getTransactionList(dateFrom, dateTo, outputFrom, outputTo); + return transactions.map((t) => this.toTransactionListEntry(t)); + } + // --- MAPPING METHODS --- // + private toTransactionListEntry(tx: Transaction): TransactionListEntry { + return { + id: tx.id, + type: tx.type, + accountId: tx.userData?.id, + name: tx.userData?.verifiedName, + domicile: tx.userData?.country?.name, + created: tx.created, + eventDate: tx.eventDate, + outputDate: tx.outputDate, + assets: tx.assets, + amountInChf: tx.amountInChf, + highRisk: tx.highRisk, + }; + } + private toKycFileListEntry(userData: UserData, auditStartDate?: Date): KycFileListEntry { return { kycFileId: userData.kycFileId, diff --git a/src/subdomains/supporting/payment/services/transaction.service.ts b/src/subdomains/supporting/payment/services/transaction.service.ts index 9e49dbf80f..19eed65e5d 100644 --- a/src/subdomains/supporting/payment/services/transaction.service.ts +++ b/src/subdomains/supporting/payment/services/transaction.service.ts @@ -129,6 +129,46 @@ export class TransactionService { }); } + async getTransactionList(dateFrom?: Date, dateTo?: Date, outputFrom?: Date, outputTo?: Date): Promise { + const query = this.repo + .createQueryBuilder('transaction') + .select('transaction') + .leftJoinAndSelect('transaction.userData', 'userData') + .leftJoinAndSelect('userData.country', 'country') + .where('transaction.type IS NOT NULL'); + + if (dateFrom || dateTo || outputFrom || outputTo) { + query.andWhere( + new Brackets((qb) => { + if (dateFrom && dateTo) { + qb.where('transaction.created BETWEEN :dateFrom AND :dateTo', { dateFrom, dateTo }); + } else if (dateFrom) { + qb.where('transaction.created >= :dateFrom', { dateFrom }); + } else if (dateTo) { + qb.where('transaction.created <= :dateTo', { dateTo }); + } + + if (outputFrom || outputTo) { + const outputCondition = + outputFrom && outputTo + ? 'transaction.outputDate BETWEEN :outputFrom AND :outputTo' + : outputFrom + ? 'transaction.outputDate >= :outputFrom' + : 'transaction.outputDate <= :outputTo'; + + if (dateFrom || dateTo) { + qb.andWhere(outputCondition, { outputFrom, outputTo }); + } else { + qb.where(outputCondition, { outputFrom, outputTo }); + } + } + }), + ); + } + + return query.orderBy('transaction.id', 'DESC').getMany(); + } + async getTransactionsForAccount(userDataId: number, from = new Date(0), to = new Date()): Promise { return this.repo.find({ where: { userData: { id: userDataId }, type: Not(IsNull()), created: Between(from, to) },