Skip to content
Draft
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
@@ -1,4 +1,5 @@
import { ConfigService } from 'src/config/config';
import { Util } from 'src/shared/utils/util';
import { KycLogService } from 'src/subdomains/generic/kyc/services/kyc-log.service';
import { NotificationService } from 'src/subdomains/supporting/notification/services/notification.service';
import { UserData } from '../../user-data/user-data.entity';
Expand All @@ -13,6 +14,7 @@ describe('AccountMergeService', () => {
let accountMergeRepo: jest.Mocked<Partial<AccountMergeRepository>>;
let notificationService: jest.Mocked<Partial<NotificationService>>;
let kycLogService: jest.Mocked<Partial<KycLogService>>;
let userDataService: jest.Mocked<Partial<UserDataService>>;

const buildUserData = (id: number, mail?: string): UserData => {
const userData = Object.assign(new UserData(), { id, mail, firstname: `user${id}` });
Expand All @@ -25,15 +27,16 @@ describe('AccountMergeService', () => {
});

beforeEach(() => {
accountMergeRepo = { findOneBy: jest.fn(), save: jest.fn() };
accountMergeRepo = { findOneBy: jest.fn(), save: jest.fn(), findOne: jest.fn(), update: jest.fn() };
notificationService = { sendMail: jest.fn() };
kycLogService = { createMergeLog: jest.fn() };
userDataService = { mergeUserData: jest.fn() };

service = new AccountMergeService(
accountMergeRepo as unknown as AccountMergeRepository,
notificationService as unknown as NotificationService,
kycLogService as unknown as KycLogService,
{} as unknown as UserDataService,
userDataService as unknown as UserDataService,
);
});

Expand Down Expand Up @@ -111,4 +114,30 @@ describe('AccountMergeService', () => {
expect((mail.input as { userData: UserData }).userData).toBe(slave);
});
});

describe('executeMerge', () => {
const buildRequest = (master: UserData, slave: UserData): AccountMerge =>
Object.assign(new AccountMerge(), {
id: 20,
code: 'code-20',
master,
slave,
isCompleted: false,
expiration: Util.daysAfter(30),
});

it('merges with notifyUser=true so the master is notified about the confirmed merge', async () => {
// master is the account with an ident document; the slave's mailbox confirmed the merge.
// Without notifyUser=true the master (the account being merged into) would never be told.
const master = buildUserData(1, 'master@test.com');
const slave = buildUserData(2, 'slave@test.com');
Object.assign(master, { identDocumentId: 'DOC-1' });
accountMergeRepo.findOne.mockResolvedValue(buildRequest(master, slave));

await service.executeMerge('code-20');

expect(userDataService.mergeUserData).toHaveBeenCalledTimes(1);
expect(userDataService.mergeUserData).toHaveBeenCalledWith(master.id, slave.id, slave.mail, true);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,10 @@ export class AccountMergeService {
await this.accountMergeRepo.update(...request.startProcessing());

try {
await this.userDataService.mergeUserData(master.id, slave.id, request.slave.mail);
// notifyUser: a merge confirmed via the e-mailed code is the one path an outside party can
// trigger (IDENT_DOCUMENT merges mail the code to the slave, not the master), so the master
// must be told its account gained an address/mail — same as the AML and admin merge callers.
await this.userDataService.mergeUserData(master.id, slave.id, request.slave.mail, true);
} catch (e) {
// clear the processing marker so a failed merge does not leave the client stuck on a
// never-ending waiting state (isProcessing would otherwise stay true until expiration)
Expand Down