Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ export class BuyCrypto extends IEntity {
refFactor: null,
usedFees: null,
networkStartFeeAmount: null,
status: null,
status: BuyCryptoStatus.CREATED,
};

Object.assign(this, update);
Expand Down
2 changes: 1 addition & 1 deletion src/subdomains/core/referral/referral.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ import { RefRewardService } from './reward/services/ref-reward.service';
RefRewardOutService,
RefRewardJobService,
],
exports: [RefService, RefRewardService, RefRewardRepository],
exports: [RefService, RefRewardService],
})
export class ReferralModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,22 @@ export class RefRewardService {
cryptoCurrency: v.outputAsset.dexName,
}));
}

async getRewardRecipients(from?: Date): Promise<{ userDataId: number; count: number; totalChf: number }[]> {
const query = this.rewardRepo
.createQueryBuilder('r')
.innerJoin('r.user', 'u')
.select('u.userDataId', 'userDataId')
.addSelect('COUNT(*)', 'count')
.addSelect('ROUND(SUM(r.amountInChf), 0)', 'totalChf')
.where('r.status != :excluded', { excluded: RewardStatus.USER_SWITCH })
.groupBy('u.userDataId')
.orderBy('totalChf', 'DESC');

if (from) {
query.andWhere('r.created >= :from', { from });
}

return query.getRawMany();
}
}
6 changes: 5 additions & 1 deletion src/subdomains/generic/kyc/dto/kyc-error.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export enum KycError {
DENIED_RECOMMENDATION = 'DeniedRecommendation',
RECOMMENDER_BLOCKED = 'RecommenderBlocked',

// FinancialData errors
// FinancialData errors/reasons
MISSING_INFO = 'MissingInfo',
RISKY_BUSINESS = 'RiskyBusiness',
INCORRECT_INFO = 'IncorrectInfo',
Expand All @@ -50,6 +50,8 @@ export enum KycError {
// DfxApproval errors
BANK_RECALL_FEE_NOT_PAID = 'BankRecallFeeNotPaid',
OPEN_SANCTIONED_NAME_CHECK = 'OpenSanctionedNameCheck',
RISK_ACCEPTED = 'RiskAccepted',
NO_GWG_RISK = 'NoGwgRisk',

// Deactivated userData errors
USER_DATA_DEACTIVATED = 'UserDataDeactivated',
Expand Down Expand Up @@ -95,6 +97,8 @@ export const KycErrorMap: Record<KycError, string> = {
[KycError.RESIDENCE_PERMIT_CHECK_REQUIRED]: undefined,
[KycError.EXPIRED_STEP]: 'Your documents are expired',
[KycError.MANUAL_REVIEW_REQUIRED]: undefined,
[KycError.RISK_ACCEPTED]: undefined,
[KycError.NO_GWG_RISK]: undefined,
};

export const KycReasonMap: { [e in KycError]?: KycStepReason } = {
Expand Down
9 changes: 4 additions & 5 deletions src/subdomains/generic/kyc/services/kyc-log.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,10 @@ export class KycLogService {
}

async getLogsByUserDataId(userDataId: number): Promise<KycLog[]> {
return this.kycLogRepo
.createQueryBuilder('log')
.where('log.userDataId = :userDataId', { userDataId })
.orderBy('log.created', 'DESC')
.getMany();
return this.kycLogRepo.find({
where: { userData: { id: userDataId } },
order: { created: 'DESC' },
});
}

async createKycFileLog(log: string, user?: UserData) {
Expand Down
30 changes: 29 additions & 1 deletion src/subdomains/generic/kyc/services/kyc.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -468,11 +468,39 @@ export class KycService {

async initializeProcess(userData: UserData): Promise<UserData> {
const user = await this.getUser(userData.kycHash);
if (user.getStepsWith(KycStepName.CONTACT_DATA).length > 0) return user;

const contactSteps = user.getStepsWith(KycStepName.CONTACT_DATA);
if (contactSteps.length > 0) {
// Complete pending ContactData step if user now has an email
const pendingStep = contactSteps.find((s) => s.isInProgress);
if (pendingStep && user.mail) {
const result = await this.trySetMail(user, pendingStep, user.mail);
await this.kycStepRepo.update(...result);
await this.createStepLog(user, pendingStep);
await this.updateProgress(user, false);
}
return user;
}

return this.updateProgress(user, true, false);
}

async failContactStepForMail(userData: UserData, mail: string, error: string): Promise<void> {
try {
const user = await this.getUser(userData.kycHash);
const pendingStep = user.getStepsWith(KycStepName.CONTACT_DATA).find((s) => s.isInProgress);
if (!pendingStep) return;

const kycError = error.includes('account merge request sent')
? KycError.USER_DATA_MERGE_REQUESTED
: KycError.USER_DATA_EXISTING;
await this.kycStepRepo.update(...pendingStep.fail({ mail }, kycError));
await this.createStepLog(user, pendingStep);
} catch (e) {
this.logger.error(`Failed to update ContactData step for account ${userData.id}:`, e);
}
}

public getMailFailedReason(comment: string, language: string): string {
return `<ul>${comment
?.split(';')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,8 @@ export class UserDataService {
if (mergeRequested) errorMessage += ' - account merge request sent';
}

await this.kycService.failContactStepForMail(userData, mail, errorMessage);

throw new ConflictException(errorMessage);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable } from '@nestjs/common';
import { AssetService } from 'src/shared/models/asset/asset.service';
import { RefRewardRepository } from '../../core/referral/reward/ref-reward.repository';
import { RefRewardService } from '../../core/referral/reward/services/ref-reward.service';
import { Log } from '../log/log.entity';
import { LogService } from '../log/log.service';
import { FinanceLog } from '../log/dto/log.dto';
Expand All @@ -19,7 +19,7 @@ export class DashboardFinancialService {
constructor(
private readonly logService: LogService,
private readonly assetService: AssetService,
private readonly refRewardRepo: RefRewardRepository,
private readonly refRewardService: RefRewardService,
) {}

async getFinancialLog(from?: Date, dailySample?: boolean): Promise<FinancialLogResponseDto> {
Expand All @@ -37,21 +37,7 @@ export class DashboardFinancialService {
}

async getRefRewardRecipients(from?: Date): Promise<RefRewardRecipientDto[]> {
const query = this.refRewardRepo
.createQueryBuilder('r')
.innerJoin('r.user', 'u')
.select('u.userDataId', 'userDataId')
.addSelect('COUNT(*)', 'count')
.addSelect('ROUND(SUM(r.amountInChf), 0)', 'totalChf')
.where('r.status != :excluded', { excluded: 'UserSwitch' })
.groupBy('u.userDataId')
.orderBy('totalChf', 'DESC');

if (from) {
query.andWhere('r.created >= :from', { from });
}

return query.getRawMany();
return this.refRewardService.getRewardRecipients(from);
}

async getLatestFinancialChanges(): Promise<FinancialChangesEntryDto | undefined> {
Expand Down
Loading