From 38a7b4a11b24fe7f750081294cab0090562c0374 Mon Sep 17 00:00:00 2001 From: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Date: Tue, 24 Feb 2026 14:19:15 +0100 Subject: [PATCH 1/8] [NOTASK] phoneCall aml refactoring --- src/subdomains/core/aml/services/aml-helper.service.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/subdomains/core/aml/services/aml-helper.service.ts b/src/subdomains/core/aml/services/aml-helper.service.ts index cf4a777d22..c4c0e5b6ce 100644 --- a/src/subdomains/core/aml/services/aml-helper.service.ts +++ b/src/subdomains/core/aml/services/aml-helper.service.ts @@ -266,12 +266,16 @@ export class AmlHelperService { errors.push(AmlError.IBAN_BLACKLISTED); if ( + !entity.userData.phoneCallCheckDate && + (!entity.userData.accountType || entity.userData.accountType === AccountType.PERSONAL) && phoneCallList.some((b) => b.matches([SpecialExternalAccountType.AML_PHONE_CALL_NEEDED_BIC_BUY], entity.bankTx.bic), ) ) errors.push(AmlError.BIC_PHONE_VERIFICATION_NEEDED); if ( + !entity.userData.phoneCallCheckDate && + (!entity.userData.accountType || entity.userData.accountType === AccountType.PERSONAL) && phoneCallList.some((b) => b.matches([SpecialExternalAccountType.AML_PHONE_CALL_NEEDED_IBAN_BUY], entity.bankTx.iban), ) From faee127353fe06ce95a496437fd807497b8c3631 Mon Sep 17 00:00:00 2001 From: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Date: Tue, 24 Feb 2026 15:00:55 +0100 Subject: [PATCH 2/8] [NOTASK] bankTx save bic from bankAccount --- .../bank-tx/bank-tx/services/bank-tx.service.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/subdomains/supporting/bank-tx/bank-tx/services/bank-tx.service.ts b/src/subdomains/supporting/bank-tx/bank-tx/services/bank-tx.service.ts index 72df8ba579..8b9739f13e 100644 --- a/src/subdomains/supporting/bank-tx/bank-tx/services/bank-tx.service.ts +++ b/src/subdomains/supporting/bank-tx/bank-tx/services/bank-tx.service.ts @@ -8,6 +8,7 @@ import { OnModuleInit, } from '@nestjs/common'; import { CronExpression } from '@nestjs/schedule'; +import * as IbanTools from 'ibantools'; import { Observable, Subject } from 'rxjs'; import { YapealService } from 'src/integration/bank/services/yapeal.service'; import { SettingService } from 'src/shared/models/setting/setting.service'; @@ -21,6 +22,7 @@ import { BankBalanceUpdate } from 'src/subdomains/core/liquidity-management/serv import { BankDataService } from 'src/subdomains/generic/user/models/bank-data/bank-data.service'; import { UserData } from 'src/subdomains/generic/user/models/user-data/user-data.entity'; import { User } from 'src/subdomains/generic/user/models/user/user.entity'; +import { BankAccountService } from 'src/subdomains/supporting/bank/bank-account/bank-account.service'; import { IbanBankName } from 'src/subdomains/supporting/bank/bank/dto/bank.dto'; import { MailContext, MailType } from 'src/subdomains/supporting/notification/enums'; import { NotificationService } from 'src/subdomains/supporting/notification/services/notification.service'; @@ -111,6 +113,7 @@ export class BankTxService implements OnModuleInit { private readonly virtualIbanService: VirtualIbanService, @Inject(forwardRef(() => TransactionNotificationService)) private readonly transactionNotificationService: TransactionNotificationService, + private readonly bankAccountService: BankAccountService, ) {} onModuleInit() { @@ -305,6 +308,12 @@ export class BankTxService implements OnModuleInit { entity.transaction = await this.transactionService.create({ sourceType: TransactionSourceType.BANK_TX }); + if (!entity.bic && entity.iban && IbanTools.validateIBAN(entity.iban).valid) + entity.bic = await this.bankAccountService + .getOrCreateIbanBankAccountInternal(entity.iban, false) + .catch(() => null) + .then((b) => b?.bic); + return this.bankTxRepo.save(entity); } @@ -484,6 +493,12 @@ export class BankTxService implements OnModuleInit { for (const tx of newTxs) { tx.transaction = await this.transactionService.create({ sourceType: TransactionSourceType.BANK_TX }); + + if (!tx.bic && tx.iban && IbanTools.validateIBAN(tx.iban).valid) + tx.bic = await this.bankAccountService + .getOrCreateIbanBankAccountInternal(tx.iban, false) + .catch(() => null) + .then((b) => b?.bic); } // store batch and entries in one transaction From 48e744d0c94d6ec7c888d0c5b355a2016df27cba Mon Sep 17 00:00:00 2001 From: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Date: Tue, 24 Feb 2026 16:29:54 +0100 Subject: [PATCH 3/8] [NOTASK] Refactoring --- src/shared/utils/util.ts | 17 ++++++ .../core/aml/services/aml-helper.service.ts | 60 ++++++++++++------- .../transaction/transaction-util.service.ts | 13 +++- .../bank-account/is-dfx-iban.validator.ts | 31 +++++++++- .../special-external-account.entity.ts | 5 ++ .../special-external-account.service.ts | 5 ++ 6 files changed, 106 insertions(+), 25 deletions(-) diff --git a/src/shared/utils/util.ts b/src/shared/utils/util.ts index a65426a8a3..b395ed8c1c 100644 --- a/src/shared/utils/util.ts +++ b/src/shared/utils/util.ts @@ -273,6 +273,23 @@ export class Util { return result || '0'; } + // --- IBAN --- // + static getBLZ(iban: string): string | undefined { + if (!iban) return undefined; + + switch (Util.getIbanCountry(iban)) { + case 'DE': + return iban.substring(4, 12); + + default: + return iban.length >= 10 ? iban.substring(4, 9) : undefined; + } + } + + static getIbanCountry(iban: string): string { + return iban.substring(0, 2); + } + // --- ID GENERATION --- // static randomId(): number { return randomBytes(4).readUInt32BE(); diff --git a/src/subdomains/core/aml/services/aml-helper.service.ts b/src/subdomains/core/aml/services/aml-helper.service.ts index c4c0e5b6ce..3ad5775e0f 100644 --- a/src/subdomains/core/aml/services/aml-helper.service.ts +++ b/src/subdomains/core/aml/services/aml-helper.service.ts @@ -252,15 +252,24 @@ export class AmlHelperService { ) errors.push(AmlError.BIC_BLACKLISTED); if ( - blacklist.some((b) => - b.matches( - [ - SpecialExternalAccountType.BANNED_IBAN, - SpecialExternalAccountType.BANNED_IBAN_BUY, - SpecialExternalAccountType.BANNED_IBAN_AML, - ], - entity.bankTx.iban, - ), + blacklist.some( + (b) => + b.matches( + [ + SpecialExternalAccountType.BANNED_IBAN, + SpecialExternalAccountType.BANNED_IBAN_BUY, + SpecialExternalAccountType.BANNED_IBAN_AML, + ], + entity.bankTx.iban, + ) || + b.matches( + [ + SpecialExternalAccountType.BANNED_BLZ, + SpecialExternalAccountType.BANNED_BLZ_BUY, + SpecialExternalAccountType.BANNED_BLZ_AML, + ], + Util.getBLZ(entity.bankTx.iban), + ), ) ) errors.push(AmlError.IBAN_BLACKLISTED); @@ -276,8 +285,10 @@ export class AmlHelperService { if ( !entity.userData.phoneCallCheckDate && (!entity.userData.accountType || entity.userData.accountType === AccountType.PERSONAL) && - phoneCallList.some((b) => - b.matches([SpecialExternalAccountType.AML_PHONE_CALL_NEEDED_IBAN_BUY], entity.bankTx.iban), + phoneCallList.some( + (b) => + b.matches([SpecialExternalAccountType.AML_PHONE_CALL_NEEDED_IBAN_BUY], entity.bankTx.iban) || + b.matches([SpecialExternalAccountType.AML_PHONE_CALL_NEEDED_BLZ_BUY], Util.getBLZ(entity.bankTx.iban)), ) ) errors.push(AmlError.IBAN_PHONE_VERIFICATION_NEEDED); @@ -332,15 +343,24 @@ export class AmlHelperService { if (entity.sell.fiat.name === 'CHF' && !Config.isDomesticIban(entity.sell.iban)) errors.push(AmlError.ABROAD_CHF_NOT_ALLOWED); if ( - blacklist.some((b) => - b.matches( - [ - SpecialExternalAccountType.BANNED_IBAN, - SpecialExternalAccountType.BANNED_IBAN_SELL, - SpecialExternalAccountType.BANNED_IBAN_AML, - ], - entity.sell.iban, - ), + blacklist.some( + (b) => + b.matches( + [ + SpecialExternalAccountType.BANNED_IBAN, + SpecialExternalAccountType.BANNED_IBAN_SELL, + SpecialExternalAccountType.BANNED_IBAN_AML, + ], + entity.sell.iban, + ) || + b.matches( + [ + SpecialExternalAccountType.BANNED_BLZ, + SpecialExternalAccountType.BANNED_BLZ_SELL, + SpecialExternalAccountType.BANNED_BLZ_AML, + ], + Util.getBLZ(entity.sell.iban), + ), ) ) errors.push(AmlError.IBAN_BLACKLISTED); diff --git a/src/subdomains/core/transaction/transaction-util.service.ts b/src/subdomains/core/transaction/transaction-util.service.ts index 4d1f8f704b..8202e75c93 100644 --- a/src/subdomains/core/transaction/transaction-util.service.ts +++ b/src/subdomains/core/transaction/transaction-util.service.ts @@ -13,6 +13,7 @@ import { BlockchainRegistryService } from 'src/integration/blockchain/shared/ser import { TxValidationService } from 'src/integration/blockchain/shared/services/tx-validation.service'; import { CheckoutPaymentStatus } from 'src/integration/checkout/dto/checkout.dto'; import { AssetService } from 'src/shared/models/asset/asset.service'; +import { Util } from 'src/shared/utils/util'; import { User } from 'src/subdomains/generic/user/models/user/user.entity'; import { BankTxReturn } from 'src/subdomains/supporting/bank-tx/bank-tx-return/bank-tx-return.entity'; import { BankAccountService } from 'src/subdomains/supporting/bank/bank-account/bank-account.service'; @@ -107,12 +108,20 @@ export class TransactionUtilService { if ( blockedAccounts.some( (b) => - [ + ([ SpecialExternalAccountType.BANNED_IBAN, SpecialExternalAccountType.BANNED_IBAN_BUY, SpecialExternalAccountType.BANNED_IBAN_SELL, SpecialExternalAccountType.BANNED_IBAN_AML, - ].includes(b.type) && b.value === iban, + ].includes(b.type) && + b.value === iban) || + ([ + SpecialExternalAccountType.BANNED_BLZ, + SpecialExternalAccountType.BANNED_BLZ_BUY, + SpecialExternalAccountType.BANNED_BLZ_SELL, + SpecialExternalAccountType.BANNED_BLZ_AML, + ].includes(b.type) && + b.value === Util.getBLZ(iban)), ) ) throw new BadRequestException('Iban not allowed'); diff --git a/src/subdomains/supporting/bank/bank-account/is-dfx-iban.validator.ts b/src/subdomains/supporting/bank/bank-account/is-dfx-iban.validator.ts index 6c9e19f331..366a57c3c7 100644 --- a/src/subdomains/supporting/bank/bank-account/is-dfx-iban.validator.ts +++ b/src/subdomains/supporting/bank/bank-account/is-dfx-iban.validator.ts @@ -8,6 +8,7 @@ import { } from 'class-validator'; import * as IbanTools from 'ibantools'; import { Config } from 'src/config/config'; +import { Util } from 'src/shared/utils/util'; import { SpecialExternalAccountType } from '../../payment/entities/special-external-account.entity'; import { SpecialExternalAccountService } from '../../payment/services/special-external-account.service'; import { Bank } from '../bank/bank.entity'; @@ -30,6 +31,7 @@ export class IsDfxIbanValidator implements ValidatorConstraintInterface { ) {} private blockedIbans: string[] = []; + private blockedBLZs: string[] = []; private blockedBICs: string[] = []; private dfxBanks: Bank[] = []; private currentBIC: string = undefined; @@ -37,11 +39,23 @@ export class IsDfxIbanValidator implements ValidatorConstraintInterface { async validate(_: string, args: ValidationArguments) { // blacklist types const type = args.constraints[0]; - const types = [SpecialExternalAccountType.BANNED_IBAN, SpecialExternalAccountType.BANNED_BIC]; + const types = [ + SpecialExternalAccountType.BANNED_IBAN, + SpecialExternalAccountType.BANNED_BLZ, + SpecialExternalAccountType.BANNED_BIC, + ]; if ([IbanType.BUY, IbanType.BOTH].includes(type)) - types.push(SpecialExternalAccountType.BANNED_IBAN_BUY, SpecialExternalAccountType.BANNED_BIC_BUY); + types.push( + SpecialExternalAccountType.BANNED_IBAN_BUY, + SpecialExternalAccountType.BANNED_BLZ_BUY, + SpecialExternalAccountType.BANNED_BIC_BUY, + ); if ([IbanType.SELL, IbanType.BOTH].includes(type)) - types.push(SpecialExternalAccountType.BANNED_IBAN_SELL, SpecialExternalAccountType.BANNED_BIC_SELL); + types.push( + SpecialExternalAccountType.BANNED_IBAN_SELL, + SpecialExternalAccountType.BANNED_BLZ_SELL, + SpecialExternalAccountType.BANNED_BIC_SELL, + ); const blacklists = await this.specialExternalAccountService.getBlacklist(types); @@ -56,6 +70,15 @@ export class IsDfxIbanValidator implements ValidatorConstraintInterface { ].includes(b.type), ) .map((b) => b.value); + this.blockedBLZs = blacklists + .filter((b) => + [ + SpecialExternalAccountType.BANNED_BLZ, + SpecialExternalAccountType.BANNED_BLZ_BUY, + SpecialExternalAccountType.BANNED_BLZ_SELL, + ].includes(b.type), + ) + .map((b) => b.value); this.blockedBICs = blacklists .filter((b) => [ @@ -86,6 +109,8 @@ export class IsDfxIbanValidator implements ValidatorConstraintInterface { const isBlocked = this.blockedIbans.some((i) => new RegExp(i.toLowerCase()).test(iban.toLowerCase())); if (isBlocked) return `${args.property} not allowed`; + if (this.blockedBLZs.some((i) => new RegExp(i).test(Util.getBLZ(iban)))) return `${args.property} not allowed`; + if (this.blockedBICs.some((b) => new RegExp(b.toLowerCase()).test(this.currentBIC?.toLowerCase()))) return `${args.property} BIC not allowed`; diff --git a/src/subdomains/supporting/payment/entities/special-external-account.entity.ts b/src/subdomains/supporting/payment/entities/special-external-account.entity.ts index ead402339a..4fcb0ebb61 100644 --- a/src/subdomains/supporting/payment/entities/special-external-account.entity.ts +++ b/src/subdomains/supporting/payment/entities/special-external-account.entity.ts @@ -12,9 +12,14 @@ export enum SpecialExternalAccountType { BANNED_BIC_BUY = 'BannedBicBuy', BANNED_BIC_SELL = 'BannedBicSell', BANNED_BIC_AML = 'BannedBicAml', + BANNED_BLZ = 'BannedBlz', + BANNED_BLZ_BUY = 'BannedBlzBuy', + BANNED_BLZ_SELL = 'BannedBlzSell', + BANNED_BLZ_AML = 'BannedBlzAml', BANNED_MAIL = 'BannedMail', BANNED_ACCOUNT_IBAN = 'BannedAccountIban', AML_PHONE_CALL_NEEDED_BIC_BUY = 'AmlPhoneCallNeededBicBuy', + AML_PHONE_CALL_NEEDED_BLZ_BUY = 'AmlPhoneCallNeededBicBuy', AML_PHONE_CALL_NEEDED_IBAN_BUY = 'AmlPhoneCallNeededIbanBuy', } diff --git a/src/subdomains/supporting/payment/services/special-external-account.service.ts b/src/subdomains/supporting/payment/services/special-external-account.service.ts index 43429f56c9..f52210f405 100644 --- a/src/subdomains/supporting/payment/services/special-external-account.service.ts +++ b/src/subdomains/supporting/payment/services/special-external-account.service.ts @@ -49,6 +49,7 @@ export class SpecialExternalAccountService { type: In([ SpecialExternalAccountType.AML_PHONE_CALL_NEEDED_BIC_BUY, SpecialExternalAccountType.AML_PHONE_CALL_NEEDED_IBAN_BUY, + SpecialExternalAccountType.AML_PHONE_CALL_NEEDED_BLZ_BUY, ]), }); } @@ -67,6 +68,10 @@ export class SpecialExternalAccountService { SpecialExternalAccountType.BANNED_BIC_AML, SpecialExternalAccountType.BANNED_MAIL, SpecialExternalAccountType.BANNED_ACCOUNT_IBAN, + SpecialExternalAccountType.BANNED_BLZ, + SpecialExternalAccountType.BANNED_BLZ_BUY, + SpecialExternalAccountType.BANNED_BLZ_SELL, + SpecialExternalAccountType.BANNED_BLZ_AML, ], ), }); From 7e93c1d9f38ec0ff9bcd195b9d23d2698769eaf6 Mon Sep 17 00:00:00 2001 From: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Date: Tue, 24 Feb 2026 17:52:46 +0100 Subject: [PATCH 4/8] [NOTASK] fix build --- .../payment/entities/special-external-account.entity.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/subdomains/supporting/payment/entities/special-external-account.entity.ts b/src/subdomains/supporting/payment/entities/special-external-account.entity.ts index 4fcb0ebb61..bbe31599a2 100644 --- a/src/subdomains/supporting/payment/entities/special-external-account.entity.ts +++ b/src/subdomains/supporting/payment/entities/special-external-account.entity.ts @@ -19,7 +19,7 @@ export enum SpecialExternalAccountType { BANNED_MAIL = 'BannedMail', BANNED_ACCOUNT_IBAN = 'BannedAccountIban', AML_PHONE_CALL_NEEDED_BIC_BUY = 'AmlPhoneCallNeededBicBuy', - AML_PHONE_CALL_NEEDED_BLZ_BUY = 'AmlPhoneCallNeededBicBuy', + AML_PHONE_CALL_NEEDED_BLZ_BUY = 'AmlPhoneCallNeededBlzBuy', AML_PHONE_CALL_NEEDED_IBAN_BUY = 'AmlPhoneCallNeededIbanBuy', } From 11f28a02ebca312fb28b50c256febd82332c0f95 Mon Sep 17 00:00:00 2001 From: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:47:00 +0100 Subject: [PATCH 5/8] [NOTASK] remove bic loading --- .../bank-tx/bank-tx/services/bank-tx.service.ts | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/subdomains/supporting/bank-tx/bank-tx/services/bank-tx.service.ts b/src/subdomains/supporting/bank-tx/bank-tx/services/bank-tx.service.ts index 8b9739f13e..72df8ba579 100644 --- a/src/subdomains/supporting/bank-tx/bank-tx/services/bank-tx.service.ts +++ b/src/subdomains/supporting/bank-tx/bank-tx/services/bank-tx.service.ts @@ -8,7 +8,6 @@ import { OnModuleInit, } from '@nestjs/common'; import { CronExpression } from '@nestjs/schedule'; -import * as IbanTools from 'ibantools'; import { Observable, Subject } from 'rxjs'; import { YapealService } from 'src/integration/bank/services/yapeal.service'; import { SettingService } from 'src/shared/models/setting/setting.service'; @@ -22,7 +21,6 @@ import { BankBalanceUpdate } from 'src/subdomains/core/liquidity-management/serv import { BankDataService } from 'src/subdomains/generic/user/models/bank-data/bank-data.service'; import { UserData } from 'src/subdomains/generic/user/models/user-data/user-data.entity'; import { User } from 'src/subdomains/generic/user/models/user/user.entity'; -import { BankAccountService } from 'src/subdomains/supporting/bank/bank-account/bank-account.service'; import { IbanBankName } from 'src/subdomains/supporting/bank/bank/dto/bank.dto'; import { MailContext, MailType } from 'src/subdomains/supporting/notification/enums'; import { NotificationService } from 'src/subdomains/supporting/notification/services/notification.service'; @@ -113,7 +111,6 @@ export class BankTxService implements OnModuleInit { private readonly virtualIbanService: VirtualIbanService, @Inject(forwardRef(() => TransactionNotificationService)) private readonly transactionNotificationService: TransactionNotificationService, - private readonly bankAccountService: BankAccountService, ) {} onModuleInit() { @@ -308,12 +305,6 @@ export class BankTxService implements OnModuleInit { entity.transaction = await this.transactionService.create({ sourceType: TransactionSourceType.BANK_TX }); - if (!entity.bic && entity.iban && IbanTools.validateIBAN(entity.iban).valid) - entity.bic = await this.bankAccountService - .getOrCreateIbanBankAccountInternal(entity.iban, false) - .catch(() => null) - .then((b) => b?.bic); - return this.bankTxRepo.save(entity); } @@ -493,12 +484,6 @@ export class BankTxService implements OnModuleInit { for (const tx of newTxs) { tx.transaction = await this.transactionService.create({ sourceType: TransactionSourceType.BANK_TX }); - - if (!tx.bic && tx.iban && IbanTools.validateIBAN(tx.iban).valid) - tx.bic = await this.bankAccountService - .getOrCreateIbanBankAccountInternal(tx.iban, false) - .catch(() => null) - .then((b) => b?.bic); } // store batch and entries in one transaction From 1c6ad9ebe6bd517d3ade388a24a1a63eb27656f3 Mon Sep 17 00:00:00 2001 From: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Date: Tue, 24 Feb 2026 21:01:10 +0100 Subject: [PATCH 6/8] [NOTASK] add helper getter --- .../core/aml/services/aml-helper.service.ts | 12 ++++-------- src/subdomains/generic/kyc/services/kyc.service.ts | 4 ++-- .../generic/kyc/services/name-check.service.ts | 3 +-- .../user/models/bank-data/bank-data.service.ts | 8 ++------ .../user/models/user-data/user-data.entity.ts | 10 ++++++---- 5 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/subdomains/core/aml/services/aml-helper.service.ts b/src/subdomains/core/aml/services/aml-helper.service.ts index 3ad5775e0f..a51dcc4cb2 100644 --- a/src/subdomains/core/aml/services/aml-helper.service.ts +++ b/src/subdomains/core/aml/services/aml-helper.service.ts @@ -218,7 +218,7 @@ export class AmlHelperService { (entity.bankTx || entity.checkoutTx) && entity.userData.phone && entity.userData.birthday && - (!entity.userData.accountType || entity.userData.accountType === AccountType.PERSONAL) && + entity.userData.isPersonalAccount && Util.yearsDiff(entity.userData.birthday) > 55 ) errors.push(AmlError.PHONE_VERIFICATION_NEEDED); @@ -276,7 +276,7 @@ export class AmlHelperService { if ( !entity.userData.phoneCallCheckDate && - (!entity.userData.accountType || entity.userData.accountType === AccountType.PERSONAL) && + entity.userData.isPersonalAccount && phoneCallList.some((b) => b.matches([SpecialExternalAccountType.AML_PHONE_CALL_NEEDED_BIC_BUY], entity.bankTx.bic), ) @@ -284,7 +284,7 @@ export class AmlHelperService { errors.push(AmlError.BIC_PHONE_VERIFICATION_NEEDED); if ( !entity.userData.phoneCallCheckDate && - (!entity.userData.accountType || entity.userData.accountType === AccountType.PERSONAL) && + entity.userData.isPersonalAccount && phoneCallList.some( (b) => b.matches([SpecialExternalAccountType.AML_PHONE_CALL_NEEDED_IBAN_BUY], entity.bankTx.iban) || @@ -462,11 +462,7 @@ export class AmlHelperService { break; case AmlRule.RULE_16: - if ( - entity instanceof BuyCrypto && - entity.userData.accountType === AccountType.PERSONAL && - !entity.userData.phoneCallCheckDate - ) + if (entity instanceof BuyCrypto && entity.userData.isPersonalAccount && !entity.userData.phoneCallCheckDate) errors.push(AmlError.PHONE_VERIFICATION_NEEDED); break; } diff --git a/src/subdomains/generic/kyc/services/kyc.service.ts b/src/subdomains/generic/kyc/services/kyc.service.ts index 3626acc275..bb893136ae 100644 --- a/src/subdomains/generic/kyc/services/kyc.service.ts +++ b/src/subdomains/generic/kyc/services/kyc.service.ts @@ -257,7 +257,7 @@ export class KycService { } else if ( errors.includes(KycError.VERIFIED_NAME_MISSING) && errors.length === 1 && - entity.userData.accountType === AccountType.PERSONAL + entity.userData.isPersonalAccount ) { await this.userDataService.updateUserDataInternal(entity.userData, { verifiedName: `${entity.userData.firstname} ${entity.userData.surname}`, @@ -1475,7 +1475,7 @@ export class KycService { identStep.userData.verifiedCountry ?? identStep.userData.country; - if (identStep.userData.accountType === AccountType.PERSONAL) { + if (identStep.userData.isPersonalAccount) { // Personal Account if (!userCountry.dfxEnable) errors.push(KycError.COUNTRY_NOT_ALLOWED); if (userCountry.manualReviewRequired) errors.push(KycError.MANUAL_REVIEW_REQUIRED); diff --git a/src/subdomains/generic/kyc/services/name-check.service.ts b/src/subdomains/generic/kyc/services/name-check.service.ts index 9f97217a62..115a72fdd1 100644 --- a/src/subdomains/generic/kyc/services/name-check.service.ts +++ b/src/subdomains/generic/kyc/services/name-check.service.ts @@ -2,7 +2,6 @@ import { Injectable, InternalServerErrorException, NotFoundException, OnModuleIn import { Util } from 'src/shared/utils/util'; import { IsNull } from 'typeorm'; import { BankData, BankDataType } from '../../user/models/bank-data/bank-data.entity'; -import { AccountType } from '../../user/models/user-data/account-type.enum'; import { UserData } from '../../user/models/user-data/user-data.entity'; import { UserDataService } from '../../user/models/user-data/user-data.service'; import { DilisenseApiData } from '../dto/input/dilisense-data.dto'; @@ -48,7 +47,7 @@ export class NameCheckService implements OnModuleInit { // ); // Personal name check - if (!bankData.userData.accountType || bankData.userData.accountType === AccountType.PERSONAL) { + if (bankData.userData.isPersonalAccount) { const { data, file } = await this.getRiskDataAndUploadPdf( bankData.userData, false, diff --git a/src/subdomains/generic/user/models/bank-data/bank-data.service.ts b/src/subdomains/generic/user/models/bank-data/bank-data.service.ts index cc391c82e4..2ee4ed1d1f 100644 --- a/src/subdomains/generic/user/models/bank-data/bank-data.service.ts +++ b/src/subdomains/generic/user/models/bank-data/bank-data.service.ts @@ -23,7 +23,6 @@ import { SpecialExternalAccountService } from 'src/subdomains/supporting/payment import { FindOptionsRelations, FindOptionsWhere, IsNull, Like, Not } from 'typeorm'; import { AccountMerge, MergeReason } from '../account-merge/account-merge.entity'; import { AccountMergeService } from '../account-merge/account-merge.service'; -import { AccountType } from '../user-data/account-type.enum'; import { KycType, UserDataStatus } from '../user-data/user-data.enum'; import { BankData, BankDataType, BankDataVerificationError } from './bank-data.entity'; import { UpdateBankDataDto } from './dto/update-bank-data.dto'; @@ -70,17 +69,14 @@ export class BankDataService { async verifyBankData(entity: BankData): Promise { try { - if ( - !entity.userData.verifiedName && - (entity.userData.accountType === AccountType.PERSONAL || entity.type === BankDataType.BANK_IN) - ) + if (!entity.userData.verifiedName && (entity.userData.isPersonalAccount || entity.type === BankDataType.BANK_IN)) await this.userDataRepo.update(...entity.userData.setVerifiedName(entity.name)); if (entity.type === BankDataType.USER) return; if ([BankDataType.IDENT, BankDataType.NAME_CHECK].includes(entity.type)) { if ( - entity.userData.accountType === AccountType.PERSONAL || + entity.userData.isPersonalAccount || entity.userData.hasCompletedStep(KycStepName.LEGAL_ENTITY) || entity.userData.hasCompletedStep(KycStepName.SOLE_PROPRIETORSHIP_CONFIRMATION) ) { diff --git a/src/subdomains/generic/user/models/user-data/user-data.entity.ts b/src/subdomains/generic/user/models/user-data/user-data.entity.ts index d5430deb17..aa6f840252 100644 --- a/src/subdomains/generic/user/models/user-data/user-data.entity.ts +++ b/src/subdomains/generic/user/models/user-data/user-data.entity.ts @@ -639,6 +639,10 @@ export class UserData extends IEntity { // --- KYC PROCESS --- // + get isPersonalAccount(): boolean { + return !this.accountType || this.accountType === AccountType.PERSONAL; + } + get hasSuspiciousMail(): boolean { return (this.mail?.split('@')[0].match(/\d/g) ?? []).length > 2; } @@ -741,7 +745,7 @@ export class UserData extends IEntity { get requiredKycFields(): string[] { return ['accountType', 'mail', 'phone', 'firstname', 'surname', 'street', 'location', 'zip', 'country'].concat( - !this.accountType || this.accountType === AccountType.PERSONAL + this.isPersonalAccount ? [] : ['organizationName', 'organizationStreet', 'organizationLocation', 'organizationZip', 'organizationCountry'], ); @@ -752,9 +756,7 @@ export class UserData extends IEntity { } get requiredInvoiceFields(): string[] { - return ['accountType'].concat( - !this.accountType || this.accountType === AccountType.PERSONAL ? ['firstname', 'surname'] : ['organizationName'], - ); + return ['accountType'].concat(this.isPersonalAccount ? ['firstname', 'surname'] : ['organizationName']); } get isInvoiceDataComplete(): boolean { From 8367d67f3b313326121de46b78a6efd5c87e4808 Mon Sep 17 00:00:00 2001 From: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Date: Fri, 27 Feb 2026 13:36:27 +0100 Subject: [PATCH 7/8] [NOTASK] Refactoring --- src/shared/utils/util.ts | 17 ----------------- .../core/aml/services/aml-helper.service.ts | 10 +++++++--- .../transaction/transaction-util.service.ts | 3 +-- .../bank/bank-account/is-dfx-iban.validator.ts | 6 ++++-- 4 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/shared/utils/util.ts b/src/shared/utils/util.ts index b395ed8c1c..a65426a8a3 100644 --- a/src/shared/utils/util.ts +++ b/src/shared/utils/util.ts @@ -273,23 +273,6 @@ export class Util { return result || '0'; } - // --- IBAN --- // - static getBLZ(iban: string): string | undefined { - if (!iban) return undefined; - - switch (Util.getIbanCountry(iban)) { - case 'DE': - return iban.substring(4, 12); - - default: - return iban.length >= 10 ? iban.substring(4, 9) : undefined; - } - } - - static getIbanCountry(iban: string): string { - return iban.substring(0, 2); - } - // --- ID GENERATION --- // static randomId(): number { return randomBytes(4).readUInt32BE(); diff --git a/src/subdomains/core/aml/services/aml-helper.service.ts b/src/subdomains/core/aml/services/aml-helper.service.ts index a51dcc4cb2..9fa383dc7d 100644 --- a/src/subdomains/core/aml/services/aml-helper.service.ts +++ b/src/subdomains/core/aml/services/aml-helper.service.ts @@ -1,3 +1,4 @@ +import * as IbanTools from 'ibantools'; import { Config, Environment } from 'src/config/config'; import { Active } from 'src/shared/models/active'; import { Country } from 'src/shared/models/country/country.entity'; @@ -268,7 +269,7 @@ export class AmlHelperService { SpecialExternalAccountType.BANNED_BLZ_BUY, SpecialExternalAccountType.BANNED_BLZ_AML, ], - Util.getBLZ(entity.bankTx.iban), + IbanTools.extractIBAN(entity.bankTx.iban).bankIdentifier, ), ) ) @@ -288,7 +289,10 @@ export class AmlHelperService { phoneCallList.some( (b) => b.matches([SpecialExternalAccountType.AML_PHONE_CALL_NEEDED_IBAN_BUY], entity.bankTx.iban) || - b.matches([SpecialExternalAccountType.AML_PHONE_CALL_NEEDED_BLZ_BUY], Util.getBLZ(entity.bankTx.iban)), + b.matches( + [SpecialExternalAccountType.AML_PHONE_CALL_NEEDED_BLZ_BUY], + IbanTools.extractIBAN(entity.bankTx.iban).bankIdentifier, + ), ) ) errors.push(AmlError.IBAN_PHONE_VERIFICATION_NEEDED); @@ -359,7 +363,7 @@ export class AmlHelperService { SpecialExternalAccountType.BANNED_BLZ_SELL, SpecialExternalAccountType.BANNED_BLZ_AML, ], - Util.getBLZ(entity.sell.iban), + IbanTools.extractIBAN(entity.sell.iban).bankIdentifier, ), ) ) diff --git a/src/subdomains/core/transaction/transaction-util.service.ts b/src/subdomains/core/transaction/transaction-util.service.ts index 8202e75c93..dada1af9b8 100644 --- a/src/subdomains/core/transaction/transaction-util.service.ts +++ b/src/subdomains/core/transaction/transaction-util.service.ts @@ -13,7 +13,6 @@ import { BlockchainRegistryService } from 'src/integration/blockchain/shared/ser import { TxValidationService } from 'src/integration/blockchain/shared/services/tx-validation.service'; import { CheckoutPaymentStatus } from 'src/integration/checkout/dto/checkout.dto'; import { AssetService } from 'src/shared/models/asset/asset.service'; -import { Util } from 'src/shared/utils/util'; import { User } from 'src/subdomains/generic/user/models/user/user.entity'; import { BankTxReturn } from 'src/subdomains/supporting/bank-tx/bank-tx-return/bank-tx-return.entity'; import { BankAccountService } from 'src/subdomains/supporting/bank/bank-account/bank-account.service'; @@ -121,7 +120,7 @@ export class TransactionUtilService { SpecialExternalAccountType.BANNED_BLZ_SELL, SpecialExternalAccountType.BANNED_BLZ_AML, ].includes(b.type) && - b.value === Util.getBLZ(iban)), + b.value === IbanTools.extractIBAN(iban).bankIdentifier), ) ) throw new BadRequestException('Iban not allowed'); diff --git a/src/subdomains/supporting/bank/bank-account/is-dfx-iban.validator.ts b/src/subdomains/supporting/bank/bank-account/is-dfx-iban.validator.ts index 366a57c3c7..6f9bdf26a8 100644 --- a/src/subdomains/supporting/bank/bank-account/is-dfx-iban.validator.ts +++ b/src/subdomains/supporting/bank/bank-account/is-dfx-iban.validator.ts @@ -8,7 +8,6 @@ import { } from 'class-validator'; import * as IbanTools from 'ibantools'; import { Config } from 'src/config/config'; -import { Util } from 'src/shared/utils/util'; import { SpecialExternalAccountType } from '../../payment/entities/special-external-account.entity'; import { SpecialExternalAccountService } from '../../payment/services/special-external-account.service'; import { Bank } from '../bank/bank.entity'; @@ -109,7 +108,10 @@ export class IsDfxIbanValidator implements ValidatorConstraintInterface { const isBlocked = this.blockedIbans.some((i) => new RegExp(i.toLowerCase()).test(iban.toLowerCase())); if (isBlocked) return `${args.property} not allowed`; - if (this.blockedBLZs.some((i) => new RegExp(i).test(Util.getBLZ(iban)))) return `${args.property} not allowed`; + const t = IbanTools.extractIBAN(iban); + + if (this.blockedBLZs.some((i) => new RegExp(i).test(IbanTools.extractIBAN(iban).bankIdentifier))) + return `${args.property} not allowed`; if (this.blockedBICs.some((b) => new RegExp(b.toLowerCase()).test(this.currentBIC?.toLowerCase()))) return `${args.property} BIC not allowed`; From 8bc20fa79534340e218be0d9ea60499f2b03ed2b Mon Sep 17 00:00:00 2001 From: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Date: Fri, 27 Feb 2026 13:38:55 +0100 Subject: [PATCH 8/8] [NOTASK] remove unused --- .../supporting/bank/bank-account/is-dfx-iban.validator.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/subdomains/supporting/bank/bank-account/is-dfx-iban.validator.ts b/src/subdomains/supporting/bank/bank-account/is-dfx-iban.validator.ts index 6f9bdf26a8..b7226c76f7 100644 --- a/src/subdomains/supporting/bank/bank-account/is-dfx-iban.validator.ts +++ b/src/subdomains/supporting/bank/bank-account/is-dfx-iban.validator.ts @@ -108,8 +108,6 @@ export class IsDfxIbanValidator implements ValidatorConstraintInterface { const isBlocked = this.blockedIbans.some((i) => new RegExp(i.toLowerCase()).test(iban.toLowerCase())); if (isBlocked) return `${args.property} not allowed`; - const t = IbanTools.extractIBAN(iban); - if (this.blockedBLZs.some((i) => new RegExp(i).test(IbanTools.extractIBAN(iban).bankIdentifier))) return `${args.property} not allowed`;