Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Sauvegarder la date de reconciliation (PIX-14392). #10165

Merged
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 @@ -28,10 +28,11 @@ const buildCertificationCandidate = function ({
prepaymentCode = null,
hasSeenCertificationInstructions = false,
accessibilityAdjustmentNeeded = false,
reconciliatedAt = null,
reconciledAt = null,
} = {}) {
sessionId = _.isUndefined(sessionId) ? buildSession().id : sessionId;
userId = _.isUndefined(userId) ? buildUser().id : userId;
reconciledAt = userId ? new Date('2020-01-02') : undefined;

const values = {
id,
Expand All @@ -57,7 +58,7 @@ const buildCertificationCandidate = function ({
prepaymentCode,
hasSeenCertificationInstructions,
accessibilityAdjustmentNeeded,
reconciliatedAt,
reconciledAt,
};

databaseBuffer.pushInsertable({
Expand Down Expand Up @@ -89,7 +90,7 @@ const buildCertificationCandidate = function ({
prepaymentCode,
hasSeenCertificationInstructions,
accessibilityAdjustmentNeeded,
reconciliatedAt,
reconciledAt,
};
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const TABLE_NAME = 'certification-candidates';
const OLD_COLUMN_NAME = 'reconciliatedAt';
const NEW_COLUMN_NAME = 'reconciledAt';

const up = async function (knex) {
await knex.schema.table(TABLE_NAME, function (table) {
table.renameColumn(OLD_COLUMN_NAME, NEW_COLUMN_NAME);
});
};

const down = async function (knex) {
await knex.schema.table(TABLE_NAME, function (table) {
table.renameColumn(NEW_COLUMN_NAME, OLD_COLUMN_NAME);
});
};

export { down, up };
23 changes: 13 additions & 10 deletions api/db/seeds/data/common/tooling/session-tooling.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ async function createDraftScoSession({
databaseBuilder,
sessionId,
organizationId,
hasJoinSession: false,
hasJoinedSession: false,
configSession,
version,
});
Expand Down Expand Up @@ -169,7 +169,7 @@ async function createDraftSession({
const certificationCandidates = await _registerCandidatesToSession({
databaseBuilder,
sessionId,
hasJoinSession: false,
hasJoinedSession: false,
configSession,
certificationCenterId,
version,
Expand Down Expand Up @@ -398,7 +398,7 @@ async function createPublishedScoSession({
databaseBuilder,
sessionId,
organizationId,
hasJoinSession: true,
hasJoinedSession: true,
configSession,
});

Expand Down Expand Up @@ -521,7 +521,7 @@ async function createPublishedSession({
const certificationCandidates = await _registerCandidatesToSession({
databaseBuilder,
sessionId,
hasJoinSession: true,
hasJoinedSession: true,
configSession,
certificationCenterId,
version,
Expand Down Expand Up @@ -551,7 +551,7 @@ async function _registerOrganizationLearnersToSession({
databaseBuilder,
sessionId,
organizationId,
hasJoinSession,
hasJoinedSession,
configSession,
version,
}) {
Expand All @@ -566,7 +566,7 @@ async function _registerOrganizationLearnersToSession({
databaseBuilder,
sessionId,
extraTimePercentages,
hasJoinSession,
hasJoinedSession,
version,
);
}
Expand All @@ -579,7 +579,7 @@ function _addCertificationCandidatesToScoSession(
databaseBuilder,
sessionId,
extraTimePercentages,
hasJoinSession,
hasJoinedSession,
version,
) {
organizationLearners.forEach((organizationLearner, index) => {
Expand All @@ -597,7 +597,8 @@ function _addCertificationCandidatesToScoSession(
sessionId,
createdAt: new Date(),
extraTimePercentage: extraTimePercentages[index % extraTimePercentages.length],
userId: hasJoinSession ? organizationLearner.userId : null,
userId: hasJoinedSession ? organizationLearner.userId : null,
reconciledAt: hasJoinedSession ? new Date() : null,
organizationLearnerId: organizationLearner.id,
authorizedToStart: false,
billingMode: null,
Expand All @@ -623,7 +624,7 @@ function _hasLearnersToRegister(configSession) {
async function _registerCandidatesToSession({
databaseBuilder,
sessionId,
hasJoinSession,
hasJoinedSession,
configSession,
certificationCenterId,
version,
Expand Down Expand Up @@ -657,7 +658,7 @@ async function _registerCandidatesToSession({

for (let i = 0; i < configSession.candidatesToRegisterCount; i++) {
let userId = null;
if (hasJoinSession) {
if (hasJoinedSession) {
userId = databaseBuilder.factory.buildUser.withRawPassword({
firstName: `firstname${i}-${sessionId}`,
lastName: `lastname${i}-${sessionId}`,
Expand Down Expand Up @@ -685,6 +686,7 @@ async function _registerCandidatesToSession({
createdAt: configSession.sessionDate,
extraTimePercentage: randomExtraTimePercentage,
userId,
reconciledAt: hasJoinedSession ? new Date() : null,
organizationLearnerId: null,
authorizedToStart: false,
billingMode: randomBillingMode,
Expand Down Expand Up @@ -770,6 +772,7 @@ async function _registerSomeCandidatesToSession({ databaseBuilder, sessionId, co
createdAt: new Date(),
extraTimePercentage: randomExtraTimePercentage,
userId: hasJoinedSession ? userId : null,
reconciledAt: hasJoinedSession ? new Date() : null,
organizationLearnerId: null,
authorizedToStart: false,
billingMode: randomBillingMode,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { normalize } from '../../../shared/infrastructure/utils/string-utils.js';
import * as certificationCandidateSerializer from '../../shared/infrastructure/serializers/jsonapi/certification-candidate-serializer.js';
import { usecases } from '../domain/usecases/index.js';
import * as enrolledCandidateRepository from '../infrastructure/repositories/enrolled-candidate-repository.js';
import * as candidateSerializer from '../infrastructure/serializers/candidate-serializer.js';
import * as enrolledCandidateSerializer from '../infrastructure/serializers/enrolled-candidate-serializer.js';

Expand Down Expand Up @@ -54,12 +53,11 @@ const validateCertificationInstructions = async function (
) {
const certificationCandidateId = request.params.certificationCandidateId;

await usecases.candidateHasSeenCertificationInstructions({
const candidate = await usecases.candidateHasSeenCertificationInstructions({
certificationCandidateId,
});
const enrolledCandidate = await enrolledCandidateRepository.get({ id: certificationCandidateId });

return dependencies.certificationCandidateSerializer.serialize(enrolledCandidate);
return dependencies.certificationCandidateSerializer.serialize(candidate);
};

const certificationCandidateController = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
/**
* @typedef {import ('./index.js').EnrolledCandidateRepository} EnrolledCandidateRepository
* @typedef {import ('../../domain/models/Candidate.js').Candidate} Candidate
*/

import { usecases } from '../../domain/usecases/index.js';

/**
* Candidate entry to a certification is a multi step process
* @param {Object} params
* @param {EnrolledCandidateRepository} params.enrolledCandidateRepository
* @returns {Promise<EnrolledCandidate>}
* @param {number} params.userId
* @param {number} params.sessionId
* @param {string} params.firstName
* @param {string} params.lastName
* @param {Date} params.birthdate
* @param {Function} params.normalizeStringFnc
* @returns {Promise<Candidate>}
*/
export const registerCandidateParticipation = async ({
userId,
Expand All @@ -17,7 +22,6 @@ export const registerCandidateParticipation = async ({
lastName,
birthdate,
normalizeStringFnc,
enrolledCandidateRepository,
}) => {
const candidate = await usecases.verifyCandidateIdentity({
userId,
Expand All @@ -28,12 +32,12 @@ export const registerCandidateParticipation = async ({
normalizeStringFnc,
});

if (!candidate.isLinkedToAUser()) {
await usecases.linkUserToCandidate({
userId,
candidate,
});
if (candidate.isLinkedToAUser()) {
return candidate;
}

return enrolledCandidateRepository.get({ id: candidate.id });
return usecases.reconcileCandidate({
userId,
candidate,
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import lodash from 'lodash';

import { normalize } from '../../../shared/infrastructure/utils/string-utils.js';
import { usecases } from '../domain/usecases/index.js';
import * as enrolledCandidateSerializer from '../infrastructure/serializers/enrolled-candidate-serializer.js';
import { serializeForParticipation } from '../infrastructure/serializers/candidate-serializer.js';
import * as sessionSerializer from '../infrastructure/serializers/session-serializer.js';
import { services } from './services/index.js';
const { trim } = lodash;
Expand Down Expand Up @@ -47,7 +47,7 @@ const createCandidateParticipation = async function (request, h) {
const lastName = trim(request.payload.data.attributes['last-name']);
const birthdate = request.payload.data.attributes['birthdate'];

const enrolledCandidate = await services.registerCandidateParticipation({
const candidate = await services.registerCandidateParticipation({
userId,
sessionId,
firstName,
Expand All @@ -56,8 +56,7 @@ const createCandidateParticipation = async function (request, h) {
normalizeStringFnc: normalize,
});

const serialized = await enrolledCandidateSerializer.serializeForParticipation(enrolledCandidate);
return h.response(serialized).created();
return h.response(serializeForParticipation(candidate)).created();
};

const sessionController = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class Candidate {
authorizedToStart = false,
sessionId,
userId,
reconciledAt,
organizationLearnerId,
billingMode,
prepaymentCode,
Expand Down Expand Up @@ -55,6 +56,7 @@ export class Candidate {
this.hasSeenCertificationInstructions = hasSeenCertificationInstructions;
this.subscriptions = subscriptions;
this.accessibilityAdjustmentNeeded = accessibilityAdjustmentNeeded;
this.reconciledAt = reconciledAt;
}

isLinkedToAUser() {
Expand All @@ -65,8 +67,9 @@ export class Candidate {
return this.userId === userId;
}

link(userId) {
reconcile(userId) {
this.userId = userId;
this.reconciledAt = new Date();
}

updateAccessibilityAdjustmentNeededStatus(newAdjustmentStatus) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
/**
* @typedef {import('../models/Subscription.js').Subscription} Subscription
* @typedef {import('../models/Candidate.js').Candidate} Candidate
*/
import _ from 'lodash';

import { SUBSCRIPTION_TYPES } from '../../../shared/domain/constants.js';

/**
* @deprecated please use Candidate model that has no differences with this model
* @see {Candidate} domain model
*/
export class EnrolledCandidate {
/**
* @param {Object} params
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
/**
* @typedef {import ('./index.js').CandidateRepository} CandidateRepository
* @typedef {import ('../models/Candidate.js').Candidate} Candidate
*/
import { CertificationCandidateNotFoundError } from '../errors.js';

/**
* @param {Object} params
* @param {number} params.certificationCandidateId
* @param {CandidateRepository} params.candidateRepository
* @returns {Candidate}
*/
const candidateHasSeenCertificationInstructions = async function ({ certificationCandidateId, candidateRepository }) {
const candidate = await candidateRepository.get({ certificationCandidateId });
Expand All @@ -15,8 +18,8 @@ const candidateHasSeenCertificationInstructions = async function ({ certificatio
}

candidate.validateCertificationInstructions();

await candidateRepository.update(candidate);
return candidate;
};

export { candidateHasSeenCertificationInstructions };
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,34 @@ import { UserNotAuthorizedToCertifyError } from '../../../../shared/domain/error
* @param {CandidateRepository} params.candidateRepository
* @param {PlacementProfileService} params.placementProfileService
*
* @returns {Promise<void>}
* @returns {Promise<Candidate>}
*/
export async function linkUserToCandidate({ userId, candidate, candidateRepository, placementProfileService }) {
export async function reconcileCandidate({ userId, candidate, candidateRepository, placementProfileService }) {
candidate.reconcile(userId);

if (candidate.hasCoreSubscription()) {
const placementProfile = await placementProfileService.getPlacementProfile({
userId,
limitDate: new Date(),
userId: candidate.userId,
limitDate: candidate.reconciledAt,
});

if (!placementProfile.isCertifiable()) {
throw new UserNotAuthorizedToCertifyError();
}
}

return _linkUser({ userId, candidate, candidateRepository });
await _saveReconcilement({ candidate, candidateRepository });
return candidate;
}

const _linkUser = withTransaction(
const _saveReconcilement = withTransaction(
/**
* @param {Object} params
* @param {number} params.userId
* @param {Candidate} params.candidate
* @param {CandidateRepository} params.candidateRepository
*/
async ({ userId, candidate, candidateRepository }) => {
candidate.link(userId);
async ({ candidate, candidateRepository }) => {
return candidateRepository.update(candidate);
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ async function _createValidCertificationCandidates({
subscriptions,
id: null,
userId: null,
reconciledAt: null,
organizationLearnerId: null,
createdAt: null,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* @typedef {import ('./index.js').SessionRepository} SessionRepository
* @typedef {import ('./index.js').UserRepository} UserRepository
* @typedef {import ('../models/Candidate.js').Candidate} Candidate
* @typedef {import ('../read-models/EnrolledCandidate.js').EnrolledCandidate} EnrolledCandidate
*/

import {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ function adaptModelToDb(candidate) {
authorizedToStart: candidate.authorizedToStart,
sessionId: candidate.sessionId,
userId: candidate.userId,
reconciledAt: candidate.reconciledAt,
organizationLearnerId: candidate.organizationLearnerId,
billingMode: candidate.billingMode,
prepaymentCode: candidate.prepaymentCode,
Expand Down
Loading
Loading