Skip to content

Commit f38d7a4

Browse files
committed
feat: implement cancel fusion functionality for identities
- Added a new method `cancelFusion` in `IdentitiesDoublonService` to handle the cancellation of identity fusion, including validation checks for the provided IDs. - Introduced `IdentitiesCancelFusionCommand` to facilitate command-line execution for cancelling identity fusions, with appropriate logging and error handling. - Enhanced the `removeInjectedValues` method to streamline the removal of injected values from identity attributes during the cancellation process.
1 parent 24060fa commit f38d7a4

File tree

2 files changed

+118
-1
lines changed

2 files changed

+118
-1
lines changed

apps/api/src/management/identities/identities-doublon.service.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ import { BadRequestException } from '@nestjs/common';
55
import { Types } from 'mongoose';
66

77
export class IdentitiesDoublonService extends AbstractIdentitiesService {
8+
private removeInjectedValues(baseValues: string[] = [], injectedValues: string[] = []): string[] {
9+
const nextValues = [...baseValues]
10+
injectedValues.forEach((injectedValue) => {
11+
const index = nextValues.findIndex((value) => value === injectedValue)
12+
if (index !== -1) {
13+
nextValues.splice(index, 1)
14+
}
15+
})
16+
return nextValues
17+
}
18+
819
public async ignoreFusionForIdentities(ids: Types.ObjectId[]) {
920
if (ids.length !== 2) {
1021
throw new BadRequestException('Deux IDs doivent être fournis pour ignorer la fusion.');
@@ -289,4 +300,71 @@ export class IdentitiesDoublonService extends AbstractIdentitiesService {
289300
await super.update(identity1._id, identity1);
290301
return identity1._id;
291302
}
303+
304+
public async cancelFusion(id1, id2) {
305+
let identity1: Identities = null
306+
let identity2: Identities & any = null
307+
try {
308+
identity1 = await this.findById<Identities>(id1)
309+
} catch (error) {
310+
throw new BadRequestException('Id1 not found')
311+
}
312+
try {
313+
identity2 = await this.findById<Identities>(id2)
314+
} catch (error) {
315+
throw new BadRequestException('Id2 not found')
316+
}
317+
318+
if (!identity1.srcFusionId || identity1.srcFusionId.toString() !== identity2._id.toString()) {
319+
throw new BadRequestException('Id1 ne contient pas de fusion avec Id2')
320+
}
321+
if (!identity2.destFusionId || identity2.destFusionId.toString() !== identity1._id.toString()) {
322+
throw new BadRequestException('Id2 ne contient pas de destination de fusion vers Id1')
323+
}
324+
325+
identity1.inetOrgPerson.employeeNumber = this.removeInjectedValues(
326+
identity1.inetOrgPerson.employeeNumber,
327+
identity2.inetOrgPerson.employeeNumber.map((value) => value.replace(/^F/, '')),
328+
)
329+
identity1.inetOrgPerson.departmentNumber = this.removeInjectedValues(
330+
identity1.inetOrgPerson.departmentNumber,
331+
identity2.inetOrgPerson.departmentNumber,
332+
)
333+
334+
if (
335+
identity1.additionalFields.objectClasses.includes('supannPerson') &&
336+
identity2.additionalFields.objectClasses.includes('supannPerson')
337+
) {
338+
const identity1SupannPerson = identity1.additionalFields.attributes.supannPerson as any
339+
const identity2SupannPerson = identity2.additionalFields.attributes.supannPerson as any
340+
341+
if (identity1SupannPerson?.supannTypeEntiteAffectation && identity2SupannPerson?.supannTypeEntiteAffectation) {
342+
identity1SupannPerson.supannTypeEntiteAffectation = this.removeInjectedValues(
343+
identity1SupannPerson.supannTypeEntiteAffectation,
344+
identity2SupannPerson.supannTypeEntiteAffectation,
345+
)
346+
}
347+
348+
if (identity1SupannPerson?.supannRefId && identity2SupannPerson?.supannRefId) {
349+
identity1SupannPerson.supannRefId = this.removeInjectedValues(
350+
identity1SupannPerson.supannRefId,
351+
identity2SupannPerson.supannRefId,
352+
)
353+
}
354+
}
355+
356+
identity1.srcFusionId = null
357+
identity1.primaryEmployeeNumber = null
358+
identity1.state = IdentityState.TO_VALIDATE
359+
360+
identity2.destFusionId = null
361+
identity2.state = IdentityState.TO_VALIDATE
362+
if (identity2.inetOrgPerson.employeeNumber?.[0]?.startsWith('F')) {
363+
identity2.inetOrgPerson.employeeNumber[0] = identity2.inetOrgPerson.employeeNumber[0].substring(1)
364+
}
365+
366+
await super.update(identity2._id, identity2)
367+
await super.update(identity1._id, identity1)
368+
return identity1._id
369+
}
292370
}

apps/api/src/management/identities/identities.command.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { Command, CommandRunner, SubCommand } from "nest-commander";
44
import { seedRequestContextId } from "~/contextId";
55
import { Identities } from "~/management/identities/_schemas/identities.schema";
66
import { IdentitiesUpsertService } from "~/management/identities/identities-upsert.service";
7+
import { IdentitiesDoublonService } from "~/management/identities/identities-doublon.service";
8+
import { Types } from "mongoose";
79

810

911
@SubCommand({ name: 'fingerprint' })
@@ -49,7 +51,44 @@ export class IdentitiesFingerprintCommand extends CommandRunner {
4951
}
5052
}
5153

52-
@Command({ name: 'identities', arguments: '<task>', subCommands: [IdentitiesFingerprintCommand] })
54+
@SubCommand({ name: 'cancel-fusion' })
55+
export class IdentitiesCancelFusionCommand extends CommandRunner {
56+
private readonly logger = new Logger(IdentitiesCancelFusionCommand.name)
57+
58+
public constructor(
59+
protected moduleRef: ModuleRef,
60+
) {
61+
super()
62+
}
63+
64+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
65+
async run(inputs: string[], options: any): Promise<void> {
66+
const id1Raw = inputs[0]
67+
const id2Raw = inputs[1]
68+
69+
if (!id1Raw || !id2Raw) {
70+
console.error('Usage: yarn run console identities cancel-fusion <id1> <id2>')
71+
return
72+
}
73+
74+
if (!Types.ObjectId.isValid(id1Raw) || !Types.ObjectId.isValid(id2Raw)) {
75+
console.error('Both <id1> and <id2> must be valid ObjectId values.')
76+
return
77+
}
78+
79+
const contextId = seedRequestContextId(this.moduleRef)
80+
const doublonService = await this.moduleRef.resolve(
81+
IdentitiesDoublonService,
82+
contextId,
83+
)
84+
85+
this.logger.log(`Cancelling fusion between ${id1Raw} and ${id2Raw} ...`)
86+
const newPrimaryId = await doublonService.cancelFusion(new Types.ObjectId(id1Raw), new Types.ObjectId(id2Raw))
87+
console.log('Fusion cancelled successfully. New primary identity:', newPrimaryId?.toString?.() ?? newPrimaryId)
88+
}
89+
}
90+
91+
@Command({ name: 'identities', arguments: '<task>', subCommands: [IdentitiesFingerprintCommand, IdentitiesCancelFusionCommand] })
5392
export class IdentitiesCommand extends CommandRunner {
5493
public constructor(protected moduleRef: ModuleRef) {
5594
super();

0 commit comments

Comments
 (0)