diff --git a/src/subdomains/supporting/support-issue/dto/support-issue-dto.mapper.ts b/src/subdomains/supporting/support-issue/dto/support-issue-dto.mapper.ts index 92dbc84e26..43c3934a8b 100644 --- a/src/subdomains/supporting/support-issue/dto/support-issue-dto.mapper.ts +++ b/src/subdomains/supporting/support-issue/dto/support-issue-dto.mapper.ts @@ -1,9 +1,14 @@ +import { CountryDtoMapper } from 'src/shared/models/country/dto/country-dto.mapper'; +import { UserData } from 'src/subdomains/generic/user/models/user-data/user-data.entity'; import { Transaction } from '../../payment/entities/transaction.entity'; import { LimitRequest } from '../entities/limit-request.entity'; import { SupportIssue } from '../entities/support-issue.entity'; import { SupportMessage } from '../entities/support-message.entity'; import { SupportIssueDto, + SupportIssueInternalAccountDataDto, + SupportIssueInternalDataDto, + SupportIssueInternalTransactionDataDto, SupportIssueLimitRequestDto, SupportIssueStateMapper, SupportIssueTransactionDto, @@ -27,6 +32,23 @@ export class SupportIssueDtoMapper { return Object.assign(new SupportIssueDto(), dto); } + static mapSupportIssueData(supportIssue: SupportIssue): SupportIssueInternalDataDto { + const dto: SupportIssueInternalDataDto = { + id: supportIssue.id, + created: supportIssue.created, + uid: supportIssue.uid, + type: supportIssue.type, + department: supportIssue.department, + reason: supportIssue.reason, + state: supportIssue.state, + name: supportIssue.name, + account: SupportIssueDtoMapper.mapUserData(supportIssue.userData), + transaction: SupportIssueDtoMapper.mapTransactionData(supportIssue.transaction), + }; + + return Object.assign(new SupportIssueInternalDataDto(), dto); + } + static mapSupportMessage(supportMessage: SupportMessage): SupportMessageDto { const dto: SupportMessageDto = { id: supportMessage.id, @@ -39,6 +61,50 @@ export class SupportIssueDtoMapper { return Object.assign(new SupportMessageDto(), dto); } + static mapUserData(userData: UserData): SupportIssueInternalAccountDataDto { + return { + id: userData.id, + status: userData.status, + verifiedName: userData.verifiedName, + completeName: userData.completeName, + accountType: userData.accountType, + kycLevel: userData.kycLevel, + depositLimit: userData.depositLimit, + annualVolume: userData.annualBuyVolume + userData.annualSellVolume + userData.annualCryptoVolume, + kycHash: userData.kycHash, + country: userData.country ? CountryDtoMapper.entityToDto(userData.country) : undefined, + }; + } + + static mapTransactionData(transaction: Transaction): SupportIssueInternalTransactionDataDto { + if (!transaction?.id) return undefined; + + const targetEntity = transaction.buyCrypto ?? transaction.buyFiat; + + return { + id: transaction.id, + sourceType: transaction.sourceType, + type: transaction.type, + amlCheck: transaction.amlCheck, + amlReason: targetEntity?.amlReason, + comment: targetEntity?.comment, + inputAmount: targetEntity?.inputAmount, + inputAsset: targetEntity?.inputAsset, + inputBlockchain: targetEntity?.cryptoInput?.asset?.blockchain, + outputAmount: targetEntity?.outputAmount, + outputAsset: targetEntity?.outputAsset.name, + outputBlockchain: transaction?.buyCrypto?.outputAsset.blockchain, + wallet: transaction.user?.wallet + ? { + name: transaction.user.wallet.displayName ?? transaction.user.wallet.name, + amlRules: transaction.user.wallet.amlRules, + isKycClient: transaction.user.wallet.isKycClient, + } + : undefined, + isComplete: targetEntity?.isComplete, + }; + } + static mapTransaction(transaction: Transaction): SupportIssueTransactionDto { if (!transaction?.id) return null; diff --git a/src/subdomains/supporting/support-issue/dto/support-issue.dto.ts b/src/subdomains/supporting/support-issue/dto/support-issue.dto.ts index 8952b051f3..207a5397d0 100644 --- a/src/subdomains/supporting/support-issue/dto/support-issue.dto.ts +++ b/src/subdomains/supporting/support-issue/dto/support-issue.dto.ts @@ -1,4 +1,12 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { Blockchain } from 'src/integration/blockchain/shared/enums/blockchain.enum'; +import { CountryDto } from 'src/shared/models/country/dto/country.dto'; +import { AmlReason } from 'src/subdomains/core/aml/enums/aml-reason.enum'; +import { CheckStatus } from 'src/subdomains/core/aml/enums/check-status.enum'; +import { AccountType } from 'src/subdomains/generic/user/models/user-data/account-type.enum'; +import { KycLevel, UserDataStatus } from 'src/subdomains/generic/user/models/user-data/user-data.enum'; +import { TransactionSourceType, TransactionTypeInternal } from '../../payment/entities/transaction.entity'; +import { Department } from '../enums/department.enum'; import { SupportIssueInternalState, SupportIssueReason, @@ -68,6 +76,125 @@ export class SupportIssueDto { limitRequest?: SupportIssueLimitRequestDto; } +export class SupportIssueInternalAccountDataDto { + @ApiProperty() + id: number; + + @ApiProperty({ enum: UserDataStatus }) + status: UserDataStatus; + + @ApiProperty() + verifiedName: string; + + @ApiProperty() + completeName: string; + + @ApiProperty({ enum: AccountType }) + accountType: AccountType; + + @ApiProperty({ enum: KycLevel }) + kycLevel: KycLevel; + + @ApiProperty() + depositLimit: number; + + @ApiProperty() + annualVolume: number; + + @ApiProperty() + kycHash: string; + + @ApiProperty({ type: CountryDto }) + country: CountryDto; +} + +export class SupportIssueInternalWalletDto { + @ApiProperty() + name: string; + + @ApiProperty() + amlRules: string; + + @ApiProperty() + isKycClient: boolean; +} + +export class SupportIssueInternalTransactionDataDto { + @ApiProperty() + id: number; + + @ApiProperty({ enum: TransactionSourceType }) + sourceType: TransactionSourceType; + + @ApiProperty({ enum: TransactionTypeInternal }) + type: TransactionTypeInternal; + + @ApiProperty({ enum: CheckStatus }) + amlCheck: CheckStatus; + + @ApiProperty({ enum: AmlReason }) + amlReason: AmlReason; + + @ApiProperty() + comment: string; + + @ApiProperty() + inputAmount: number; + + @ApiProperty() + inputAsset: string; + + @ApiPropertyOptional({ enum: Blockchain }) + inputBlockchain?: Blockchain; + + @ApiProperty() + outputAmount: number; + + @ApiProperty() + outputAsset: string; + + @ApiPropertyOptional({ enum: Blockchain }) + outputBlockchain?: Blockchain; + + @ApiProperty({ type: SupportIssueInternalWalletDto }) + wallet: SupportIssueInternalWalletDto; + + @ApiProperty() + isComplete: boolean; +} + +export class SupportIssueInternalDataDto { + @ApiProperty() + id: number; + + @ApiProperty({ type: Date }) + created: Date; + + @ApiProperty() + uid: string; + + @ApiProperty({ enum: SupportIssueType }) + type: SupportIssueType; + + @ApiProperty({ enum: Department }) + department?: Department; + + @ApiProperty({ enum: SupportIssueReason }) + reason: SupportIssueReason; + + @ApiProperty({ enum: SupportIssueInternalState }) + state: SupportIssueInternalState; + + @ApiProperty() + name: string; + + @ApiProperty({ type: SupportIssueInternalAccountDataDto }) + account: SupportIssueInternalAccountDataDto; + + @ApiProperty({ type: SupportIssueInternalTransactionDataDto }) + transaction: SupportIssueInternalTransactionDataDto; +} + export const SupportIssueStateMapper: { [key in SupportIssueInternalState]: SupportIssueState; } = { diff --git a/src/subdomains/supporting/support-issue/services/support-issue.service.ts b/src/subdomains/supporting/support-issue/services/support-issue.service.ts index ad29ba869a..725cf1b0bd 100644 --- a/src/subdomains/supporting/support-issue/services/support-issue.service.ts +++ b/src/subdomains/supporting/support-issue/services/support-issue.service.ts @@ -7,6 +7,7 @@ import { } from '@nestjs/common'; import { Config } from 'src/config/config'; import { BlobContent } from 'src/integration/infrastructure/azure-storage.service'; +import { FiatService } from 'src/shared/models/fiat/fiat.service'; import { Util } from 'src/shared/utils/util'; import { ContentType } from 'src/subdomains/generic/kyc/enums/content-type.enum'; import { BankDataService } from 'src/subdomains/generic/user/models/bank-data/bank-data.service'; @@ -21,7 +22,7 @@ import { CreateSupportIssueBaseDto, CreateSupportIssueDto } from '../dto/create- import { CreateSupportMessageDto } from '../dto/create-support-message.dto'; import { GetSupportIssueFilter } from '../dto/get-support-issue.dto'; import { SupportIssueDtoMapper } from '../dto/support-issue-dto.mapper'; -import { SupportIssueDto, SupportMessageDto } from '../dto/support-issue.dto'; +import { SupportIssueDto, SupportIssueInternalDataDto, SupportMessageDto } from '../dto/support-issue.dto'; import { UpdateSupportIssueDto } from '../dto/update-support-issue.dto'; import { SupportIssue } from '../entities/support-issue.entity'; import { CustomerAuthor, SupportMessage } from '../entities/support-message.entity'; @@ -48,6 +49,7 @@ export class SupportIssueService { private readonly transactionRequestService: TransactionRequestService, private readonly supportLogService: SupportLogService, private readonly bankDataService: BankDataService, + private readonly fiatService: FiatService, ) {} async createTransactionRequestIssue(dto: CreateSupportIssueBaseDto): Promise { @@ -213,6 +215,22 @@ export class SupportIssueService { return SupportIssueDtoMapper.mapSupportIssue(issue); } + async getIssueData(id: number): Promise { + const issue = await this.supportIssueRepo.findOne({ + where: { id }, + relations: { + transaction: { + user: { wallet: true }, + buyCrypto: { transaction: true, cryptoInput: true }, + buyFiat: { transaction: true, cryptoInput: true }, + }, + }, + }); + if (!issue) throw new NotFoundException('Support issue not found'); + + return SupportIssueDtoMapper.mapSupportIssueData(issue); + } + async getIssueFile(id: string, messageId: number, userDataId?: number): Promise { const message = await this.messageRepo.findOneBy({ id: messageId, issue: this.getIssueSearch(id, userDataId) }); if (!message) throw new NotFoundException('Message not found'); diff --git a/src/subdomains/supporting/support-issue/support-issue.controller.ts b/src/subdomains/supporting/support-issue/support-issue.controller.ts index 3280a14232..27865086fd 100644 --- a/src/subdomains/supporting/support-issue/support-issue.controller.ts +++ b/src/subdomains/supporting/support-issue/support-issue.controller.ts @@ -11,7 +11,7 @@ import { UserRole } from 'src/shared/auth/user-role.enum'; import { CreateSupportIssueDto, CreateSupportIssueSupportDto } from './dto/create-support-issue.dto'; import { CreateSupportMessageDto } from './dto/create-support-message.dto'; import { GetSupportIssueFilter } from './dto/get-support-issue.dto'; -import { SupportIssueDto, SupportMessageDto } from './dto/support-issue.dto'; +import { SupportIssueDto, SupportIssueInternalDataDto, SupportMessageDto } from './dto/support-issue.dto'; import { UpdateSupportIssueDto } from './dto/update-support-issue.dto'; import { SupportIssue } from './entities/support-issue.entity'; import { CustomerAuthor } from './entities/support-message.entity'; @@ -65,6 +65,14 @@ export class SupportIssueController { return this.supportIssueService.getIssue(id, query, jwt?.account); } + @Get(':id/data') + @ApiBearerAuth() + @ApiExcludeEndpoint() + @UseGuards(AuthGuard(), RoleGuard(UserRole.SUPPORT), UserActiveGuard()) + async getIssueData(@Param('id') id: string): Promise { + return this.supportIssueService.getIssueData(+id); + } + @Post(':id/message') @ApiBearerAuth() @UseGuards(OptionalJwtAuthGuard)