Skip to content

Commit fa5773b

Browse files
[FEATURE] Ajout de l'API getLegalDocumentStatusByUserId dans legal-document context (PIX-15581)
#10786
2 parents fb63425 + 10c267c commit fa5773b

25 files changed

+730
-72
lines changed

api/db/database-builder/factory/build-legal-document-version.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import { databaseBuffer } from '../database-buffer.js';
22

33
const buildLegalDocumentVersion = function ({
44
id = databaseBuffer.getNextId(),
5-
type,
65
service,
6+
type,
77
versionAt = new Date(),
88
} = {}) {
99
return databaseBuffer.pushInsertable({
1010
tableName: 'legal-document-versions',
11-
values: { id, type, service, versionAt },
11+
values: { id, service, type, versionAt },
1212
});
1313
};
1414

Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
11
import { usecases } from '../../domain/usecases/index.js';
22

33
/**
4-
* Accept legal document by user id.
4+
* Accepts a legal document for a user by their ID.
55
*
6-
* @param{string} params.service
7-
* @param{string} params.type
8-
* @param{string} params.userId
6+
* @param {Object} params - The parameters.
7+
* @param {string} params.userId - The ID of the user.
8+
* @param {string} params.service - The service associated with the legal document. (e.g. 'pix-orga')
9+
* @param {string} params.type - The type of the legal document. (e.g. 'TOS')
10+
* @returns {Promise<void>} - A promise that resolves when the legal document is accepted.
11+
*/
12+
const acceptLegalDocumentByUserId = async ({ userId, service, type }) => {
13+
return usecases.acceptLegalDocumentByUserId({ userId, service, type });
14+
};
15+
16+
/**
17+
* Gets the status of a legal document for a user by their ID.
918
*
10-
* @returns {Promise<void>}
19+
* @param {Object} params - The parameters.
20+
* @param {string} params.userId - The ID of the user.
21+
* @param {string} params.service - The service associated with the legal document. (e.g. 'pix-orga')
22+
* @param {string} params.type - The type of the legal document. (e.g. 'TOS')
23+
* @returns {Promise<LegalDocumentStatus>} - A promise that resolves with the status of the legal document.
1124
*/
12-
const acceptLegalDocumentByUserId = async ({ type, service, userId }) => {
13-
return usecases.acceptLegalDocumentByUserId({ type, service, userId });
25+
const getLegalDocumentStatusByUserId = async ({ userId, service, type }) => {
26+
return usecases.getLegalDocumentStatusByUserId({ userId, service, type });
1427
};
1528

16-
export { acceptLegalDocumentByUserId };
29+
export { acceptLegalDocumentByUserId, getLegalDocumentStatusByUserId };
+12-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
import { DomainError } from '../../shared/domain/errors.js';
22

33
class LegalDocumentInvalidDateError extends DomainError {
4-
constructor({
5-
code = 'LEGAL_DOCUMENT_INVALID_DATE',
6-
message = 'Document version must not be before or equal to same document type and service',
7-
} = {}) {
8-
super(message);
9-
this.code = code;
4+
constructor() {
5+
super(
6+
'Document version must not be before or equal to same document service and type',
7+
'LEGAL_DOCUMENT_INVALID_DATE',
8+
);
109
}
1110
}
1211

13-
export { LegalDocumentInvalidDateError };
12+
class LegalDocumentVersionNotFoundError extends DomainError {
13+
constructor() {
14+
super('No legal document version found for service and type', 'LEGAL_DOCUMENT_VERSION_NOT_FOUND');
15+
}
16+
}
17+
18+
export { LegalDocumentInvalidDateError, LegalDocumentVersionNotFoundError };
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
1+
import dayjs from 'dayjs';
2+
13
export class LegalDocument {
2-
constructor({ id, type, service, versionAt }) {
4+
constructor({ id, service, type, versionAt }) {
35
this.id = id;
4-
this.type = type;
56
this.service = service;
7+
this.type = type;
68
this.versionAt = versionAt;
79
}
10+
11+
buildDocumentPath() {
12+
const service = this.service.toLowerCase();
13+
const type = this.type.toLowerCase();
14+
const versionAt = dayjs(this.versionAt).format('YYYY-MM-DD');
15+
return `${service}-${type}-${versionAt}`;
16+
}
817
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
export const STATUS = {
2+
ACCEPTED: 'accepted',
3+
REQUESTED: 'requested',
4+
UPDATE_REQUESTED: 'update-requested',
5+
};
6+
7+
export class LegalDocumentStatus {
8+
constructor({ status, acceptedAt, documentPath }) {
9+
this.status = status;
10+
this.acceptedAt = acceptedAt;
11+
this.documentPath = documentPath;
12+
}
13+
14+
/**
15+
* Builds a LegalDocumentStatus based on legacy PixOrga CGU.
16+
*
17+
* @param {Object} userPixOrgaCgu - The user object.
18+
* @param {boolean} userPixOrgaCgu.pixOrgaTermsOfServiceAccepted - Indicates if the PixOrga terms of service are accepted.
19+
* @param {Date} userPixOrgaCgu.lastPixOrgaTermsOfServiceValidatedAt - The date when the PixOrga terms of service were last validated.
20+
* @returns {LegalDocumentStatus} The legal document status.
21+
*/
22+
static buildForLegacyPixOrgaCgu(userPixOrgaCgu) {
23+
const LEGACY_PIXORGA_TOS_PATH = 'pix-orga-tos-2024-01-02';
24+
const { pixOrgaTermsOfServiceAccepted, lastPixOrgaTermsOfServiceValidatedAt } = userPixOrgaCgu;
25+
26+
return new LegalDocumentStatus({
27+
status: pixOrgaTermsOfServiceAccepted ? STATUS.ACCEPTED : STATUS.REQUESTED,
28+
acceptedAt: lastPixOrgaTermsOfServiceValidatedAt,
29+
documentPath: LEGACY_PIXORGA_TOS_PATH,
30+
});
31+
}
32+
33+
/**
34+
* Builds a LegalDocumentStatus based on the last document version and user acceptance.
35+
*
36+
* @param {Object} lastDocumentVersion - The last document version object.
37+
* @param {string} lastDocumentVersion.id - The ID of the last document version.
38+
* @param {Object} lastUserAcceptance - The last user acceptance object.
39+
* @param {string} lastUserAcceptance.legalDocumentVersionId - The ID of the accepted legal document version.
40+
* @param {Date} lastUserAcceptance.acceptedAt - The date when the document was accepted.
41+
* @returns {LegalDocumentStatus} The legal document status.
42+
*/
43+
static build(lastDocumentVersion, lastUserAcceptance) {
44+
const documentPath = lastDocumentVersion.buildDocumentPath();
45+
46+
if (!lastUserAcceptance) {
47+
return new LegalDocumentStatus({ status: STATUS.REQUESTED, acceptedAt: null, documentPath });
48+
}
49+
50+
const { legalDocumentVersionId, acceptedAt } = lastUserAcceptance;
51+
if (lastDocumentVersion.id === legalDocumentVersionId) {
52+
return new LegalDocumentStatus({ status: STATUS.ACCEPTED, acceptedAt, documentPath });
53+
}
54+
55+
return new LegalDocumentStatus({ status: STATUS.UPDATE_REQUESTED, acceptedAt: null, documentPath });
56+
}
57+
}

api/src/legal-documents/domain/usecases/accept-legal-document-by-user-id.usecase.js

+10-7
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,39 @@
11
import { LegalDocumentService } from '../models/LegalDocumentService.js';
22
import { LegalDocumentType } from '../models/LegalDocumentType.js';
33

4-
const { TOS } = LegalDocumentType.VALUES;
54
const { PIX_ORGA } = LegalDocumentService.VALUES;
5+
const { TOS } = LegalDocumentType.VALUES;
66

77
/**
88
* Accepts a legal document by user ID.
99
*
1010
* @param {Object} params - The parameters.
11-
* @param {string} params.type - The type of the legal document.
12-
* @param {string} params.service - The service of the legal document.
1311
* @param {string} params.userId - The ID of the user.
12+
* @param {string} params.service - The service of the legal document.
13+
* @param {string} params.type - The type of the legal document.
1414
* @returns {Promise<void>} A promise that resolves when the operation is complete.
1515
*/
1616
const acceptLegalDocumentByUserId = async ({
17-
type,
18-
service,
1917
userId,
18+
service,
19+
type,
2020
userRepository,
2121
legalDocumentRepository,
2222
userAcceptanceRepository,
2323
logger,
2424
}) => {
25+
LegalDocumentType.assert(type);
26+
LegalDocumentService.assert(service);
27+
2528
// legacy document acceptance
2629
if (type === TOS && service === PIX_ORGA) {
2730
await userRepository.setPixOrgaCguByUserId(userId);
2831
}
2932

3033
// new document acceptance
31-
const legalDocument = await legalDocumentRepository.findLastVersionByTypeAndService({ type, service });
34+
const legalDocument = await legalDocumentRepository.findLastVersionByTypeAndService({ service, type });
3235
if (!legalDocument) {
33-
logger.warn(`No legal document found for type: ${type} and service: ${service}`);
36+
logger.warn(`No legal document found for service: ${service} and type: ${type}`);
3437
return;
3538
}
3639

api/src/legal-documents/domain/usecases/create-legal-document.usecase.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,22 @@ import { LegalDocumentType } from '../models/LegalDocumentType.js';
66
* Creates a new legal document.
77
*
88
* @param {Object} params - The parameters.
9-
* @param {string} params.type - The type of the legal document.
109
* @param {string} params.service - The service of the legal document.
10+
* @param {string} params.type - The type of the legal document.
1111
* @param {string} params.versionAt - Version date of the new legal document.
1212
* @returns {Promise<LegalDocument>} A promise that resolves the new legal document.
1313
*/
14-
const createLegalDocument = async ({ type, service, versionAt, legalDocumentRepository }) => {
15-
LegalDocumentType.assert(type);
14+
const createLegalDocument = async ({ service, type, versionAt, legalDocumentRepository }) => {
1615
LegalDocumentService.assert(service);
16+
LegalDocumentType.assert(type);
1717

18-
const lastDocument = await legalDocumentRepository.findLastVersionByTypeAndService({ type, service });
18+
const lastDocument = await legalDocumentRepository.findLastVersionByTypeAndService({ service, type });
1919

2020
if (lastDocument && lastDocument.versionAt >= versionAt) {
2121
throw new LegalDocumentInvalidDateError();
2222
}
2323

24-
return legalDocumentRepository.create({ type, service, versionAt });
24+
return legalDocumentRepository.create({ service, type, versionAt });
2525
};
2626

2727
export { createLegalDocument };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { config } from '../../../shared/config.js';
2+
import { LegalDocumentVersionNotFoundError } from '../errors.js';
3+
import { LegalDocumentService } from '../models/LegalDocumentService.js';
4+
import { LegalDocumentStatus } from '../models/LegalDocumentStatus.js';
5+
import { LegalDocumentType } from '../models/LegalDocumentType.js';
6+
7+
/**
8+
* Gets the legal document status by user ID.
9+
*
10+
* @param {Object} params - The parameters.
11+
* @param {string} params.userId - The user ID.
12+
* @param {string} params.service - The service associated with the legal document.
13+
* @param {string} params.type - The type of the legal document.
14+
* @returns {Promise<LegalDocumentStatus>} The legal document status.
15+
* @throws {Error} If no legal document version is found for the type and service.
16+
*/
17+
const getLegalDocumentStatusByUserId = async ({
18+
userId,
19+
service,
20+
type,
21+
userRepository,
22+
legalDocumentRepository,
23+
userAcceptanceRepository,
24+
featureToggles = config.featureToggles,
25+
}) => {
26+
LegalDocumentService.assert(service);
27+
LegalDocumentType.assert(type);
28+
29+
const { isLegalDocumentsVersioningEnabled } = featureToggles;
30+
31+
if (!isLegalDocumentsVersioningEnabled) {
32+
const user = await userRepository.findPixOrgaCgusByUserId(userId);
33+
return LegalDocumentStatus.buildForLegacyPixOrgaCgu(user);
34+
}
35+
36+
const lastLegalDocument = await legalDocumentRepository.findLastVersionByTypeAndService({ service, type });
37+
38+
if (!lastLegalDocument) throw new LegalDocumentVersionNotFoundError();
39+
40+
const lastUserAcceptance = await userAcceptanceRepository.findLastForLegalDocument({ userId, service, type });
41+
42+
return LegalDocumentStatus.build(lastLegalDocument, lastUserAcceptance);
43+
};
44+
45+
export { getLegalDocumentStatusByUserId };

api/src/legal-documents/domain/usecases/index.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { dirname, join } from 'node:path';
22
import { fileURLToPath } from 'node:url';
33

4-
import { config } from '../../../shared/config.js';
54
import { injectDependencies } from '../../../shared/infrastructure/utils/dependency-injection.js';
65
import { importNamedExportsFromDirectory } from '../../../shared/infrastructure/utils/import-named-exports-from-directory.js';
76
import { logger } from '../../../shared/infrastructure/utils/logger.js';
@@ -17,7 +16,7 @@ const repositories = {
1716
userRepository,
1817
};
1918

20-
const dependencies = Object.assign({ config, logger }, repositories);
19+
const dependencies = Object.assign({ logger }, repositories);
2120

2221
const usecasesWithoutInjectedDependencies = {
2322
...(await importNamedExportsFromDirectory({ path: join(path, './'), ignoredFileNames: ['index.js'] })),

api/src/legal-documents/infrastructure/repositories/legal-document.repository.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ const TABLE_NAME = 'legal-document-versions';
77
* Retrieves the latest version of a legal document by type and service.
88
*
99
* @param {Object} params - The parameters.
10-
* @param {string} params.type - The type of the legal document.
1110
* @param {string} params.service - The service associated with the legal document.
11+
* @param {string} params.type - The type of the legal document.
1212
* @returns {Promise<LegalDocument|null>} The latest version of the legal document or null if not found.
1313
*/
14-
const findLastVersionByTypeAndService = async ({ type, service }) => {
14+
const findLastVersionByTypeAndService = async ({ service, type }) => {
1515
const knexConnection = DomainTransaction.getConnection();
1616
const documentVersionDto = await knexConnection(TABLE_NAME)
17-
.where({ type, service })
17+
.where({ service, type })
1818
.orderBy('versionAt', 'desc')
1919
.first();
2020

@@ -27,15 +27,15 @@ const findLastVersionByTypeAndService = async ({ type, service }) => {
2727
* Creates a new legal document in the database.
2828
*
2929
* @param {Object} params - The parameters.
30-
* @param {string} params.type - The type of the legal document.
3130
* @param {string} params.service - The service associated with the legal document.
31+
* @param {string} params.type - The type of the legal document.
3232
* @param {Date} params.versionAt - The date of the legal document version.
3333
* @returns {Promise<LegalDocument>} The newly created legal document.
3434
*/
35-
const create = async ({ type, service, versionAt }) => {
35+
const create = async ({ service, type, versionAt }) => {
3636
const knexConnection = DomainTransaction.getConnection();
3737

38-
const [documentVersionDto] = await knexConnection(TABLE_NAME).insert({ type, service, versionAt }).returning('*');
38+
const [documentVersionDto] = await knexConnection(TABLE_NAME).insert({ service, type, versionAt }).returning('*');
3939

4040
return new LegalDocument(documentVersionDto);
4141
};

api/src/legal-documents/infrastructure/repositories/user-acceptance.repository.js

+31-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { DomainTransaction } from '../../../shared/domain/DomainTransaction.js';
22

3+
const TABLE_NAME = 'legal-document-version-user-acceptances';
4+
35
/**
46
* Creates a new user acceptance record for a legal document version.
57
*
@@ -10,7 +12,34 @@ import { DomainTransaction } from '../../../shared/domain/DomainTransaction.js';
1012
*/
1113
const create = async ({ userId, legalDocumentVersionId }) => {
1214
const knexConnection = DomainTransaction.getConnection();
13-
await knexConnection('legal-document-version-user-acceptances').insert({ userId, legalDocumentVersionId });
15+
await knexConnection(TABLE_NAME).insert({ userId, legalDocumentVersionId });
16+
};
17+
18+
/**
19+
* Finds the last user acceptance record for a specific legal document type and service.
20+
*
21+
* @param {Object} params - The parameters for finding the user acceptance.
22+
* @param {string} params.userId - The ID of the user.
23+
* @param {string} params.service - The service associated with the legal document.
24+
* @param {string} params.type - The type of the legal document.
25+
* @returns {Promise<Object|null>} A promise that resolves to the user acceptance record or null if not found.
26+
*/
27+
const findLastForLegalDocument = async ({ userId, service, type }) => {
28+
const knexConnection = DomainTransaction.getConnection();
29+
const userAcceptanceDto = await knexConnection(TABLE_NAME)
30+
.select('userId', 'legalDocumentVersionId', 'acceptedAt')
31+
.join(
32+
'legal-document-versions',
33+
'legal-document-version-user-acceptances.legalDocumentVersionId',
34+
'legal-document-versions.id',
35+
)
36+
.where({ userId, service, type })
37+
.orderBy('versionAt', 'desc')
38+
.first();
39+
40+
if (!userAcceptanceDto) return null;
41+
42+
return userAcceptanceDto;
1443
};
1544

16-
export { create };
45+
export { create, findLastForLegalDocument };

0 commit comments

Comments
 (0)