Skip to content

Commit

Permalink
[FEATURE] Bloquer le scoring des certifications Pix+ seule (PIX-14716)
Browse files Browse the repository at this point in the history
  • Loading branch information
pix-service-auto-merge authored Nov 14, 2024
2 parents 6806b0d + 68d6f1a commit fc8f3ae
Show file tree
Hide file tree
Showing 6 changed files with 269 additions and 10 deletions.
9 changes: 6 additions & 3 deletions api/lib/domain/events/handle-certification-rescoring.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AssessmentResultFactory } from '../../../src/certification/scoring/domain/models/factories/AssessmentResultFactory.js';
import { SessionVersion } from '../../../src/certification/shared/domain/models/SessionVersion.js';
import { AlgorithmEngineVersion } from '../../../src/certification/shared/domain/models/AlgorithmEngineVersion.js';
import { V3_REPRODUCIBILITY_RATE } from '../../../src/shared/domain/constants.js';
import { CertificationComputeError } from '../../../src/shared/domain/errors.js';
import { CertificationResult } from '../../../src/shared/domain/models/CertificationResult.js';
Expand Down Expand Up @@ -35,8 +35,11 @@ async function handleCertificationRescoring({
certificationCourseId: event.certificationCourseId,
});

// TODO: switch to certif-course version, not session
if (SessionVersion.isV3(certificationAssessment.version)) {
if (certificationAssessment.isScoringBlockedDueToComplementaryOnlyChallenges) {
return;
}

if (AlgorithmEngineVersion.isV3(certificationAssessment.version)) {
return _handleV3CertificationScoring({
certificationAssessment,
event,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export class CertificationCompletedJobController extends JobController {
const certificationAssessment = await certificationAssessmentRepository.get(assessmentId);
let certificationScoringCompletedEvent;

if (certificationAssessment.isScoringBlockedDueToComplementaryOnlyChallenges) {
return;
}

if (AlgorithmEngineVersion.isV3(certificationAssessment.version)) {
certificationScoringCompletedEvent = await _handleV3CertificationScoring({
certificationAssessment,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,16 @@ class CertificationAssessment {
return [states.STARTED, states.ENDED_BY_SUPERVISOR, states.ENDED_DUE_TO_FINALIZATION];
}

get isComplementaryOnly() {
return this.certificationChallenges.every(
(certificationChallenge) => certificationChallenge.certifiableBadgeKey !== null,
);
}

get isScoringBlockedDueToComplementaryOnlyChallenges() {
return this.isComplementaryOnly;
}

_getLastChallenge() {
return _.orderBy(this.certificationChallenges, 'createdAt', 'desc')[0];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { CertificationCompletedJob } from '../../../../../../lib/domain/events/C
import { CertificationScoringCompleted } from '../../../../../../lib/domain/events/CertificationScoringCompleted.js';
import { CertificationCompletedJobController } from '../../../../../../src/certification/evaluation/application/jobs/certification-completed-job-controller.js';
import { AssessmentResultFactory } from '../../../../../../src/certification/scoring/domain/models/factories/AssessmentResultFactory.js';
import { AlgorithmEngineVersion } from '../../../../../../src/certification/shared/domain/models/AlgorithmEngineVersion.js';
import {
ABORT_REASONS,
CertificationCourse,
Expand Down Expand Up @@ -81,6 +82,7 @@ describe('Unit | Certification | Application | jobs | CertificationCompletedJobC
id: assessmentId,
certificationCourseId,
userId,
version: AlgorithmEngineVersion.V2,
});
certificationAssessmentRepository.get.withArgs(assessmentId).resolves(certificationAssessment);
});
Expand Down Expand Up @@ -265,6 +267,53 @@ describe('Unit | Certification | Application | jobs | CertificationCompletedJobC
});
});
});

context('when assessment only has only complementary certification challenges', function () {
it('should return', async function () {
// given
const certificationAssessmentWithOnlyComplementaryCertificationChallenges =
domainBuilder.buildCertificationAssessment({
id: assessmentId,
certificationCourseId,
userId,
version: AlgorithmEngineVersion.V2,
certificationChallenges: [
domainBuilder.buildCertificationChallengeWithType({
id: 1234,
certifiableBadgeKey: 'TOTO',
}),
domainBuilder.buildCertificationChallengeWithType({
id: 567,
certifiableBadgeKey: 'TOTO',
}),
domainBuilder.buildCertificationChallengeWithType({
id: 8910,
certifiableBadgeKey: 'TOTO',
}),
],
});
certificationAssessmentRepository.get
.withArgs(assessmentId)
.resolves(certificationAssessmentWithOnlyComplementaryCertificationChallenges);

const dependencies = {
assessmentResultRepository,
certificationAssessmentRepository,
certificationCourseRepository,
competenceMarkRepository,
scoringCertificationService,
services,
events,
};

// when
await certificationCompletedJobController.handle({ data, dependencies });

// then
expect(certificationCourseRepository.update).to.not.have.been.called;
expect(events.eventDispatcher.dispatch).to.not.have.been.called;
});
});
});

context('when certification is V3', function () {
Expand All @@ -285,7 +334,7 @@ describe('Unit | Certification | Application | jobs | CertificationCompletedJobC
certificationCourseId,
userId,
createdAt: Symbol('someCreationDate'),
version: 3,
version: AlgorithmEngineVersion.V3,
};
certificationAssessmentRepository.get.withArgs(assessmentId).resolves(certificationAssessment);
certificationCourse = domainBuilder.buildCertificationCourse({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -911,4 +911,158 @@ describe('Unit | Domain | Models | CertificationAssessment', function () {
]);
});
});

describe('#get isComplementaryOnly', function () {
it('should return true if challenges are only complementary', function () {
//given
const certificationAssessment = domainBuilder.buildCertificationAssessment({
certificationChallenges: [
domainBuilder.buildCertificationChallengeWithType({
challengeId: 'rec123',
certifiableBadgeKey: 'TOTO',
}),
domainBuilder.buildCertificationChallengeWithType({
challengeId: 'rec456',
certifiableBadgeKey: 'TOTO',
}),
domainBuilder.buildCertificationChallengeWithType({
challengeId: 'rec789',
certifiableBadgeKey: 'TOTO',
}),
],
certificationAnswersByDate: [
domainBuilder.buildAnswer({
challengeId: 'rec123',
}),
domainBuilder.buildAnswer({
challengeId: 'rec456',
}),
domainBuilder.buildAnswer({
challengeId: 'rec789',
}),
],
});

// when
const isComplementaryOnly = certificationAssessment.isComplementaryOnly;

// then
expect(isComplementaryOnly).to.be.true;
});

it('should return false if challenges are not complementary', function () {
//given
const certificationAssessment = domainBuilder.buildCertificationAssessment({
certificationChallenges: [
domainBuilder.buildCertificationChallengeWithType({
challengeId: 'rec123',
certifiableBadgeKey: null,
}),
domainBuilder.buildCertificationChallengeWithType({
challengeId: 'rec456',
certifiableBadgeKey: null,
}),
domainBuilder.buildCertificationChallengeWithType({
challengeId: 'rec789',
certifiableBadgeKey: null,
}),
],
certificationAnswersByDate: [
domainBuilder.buildAnswer({
challengeId: 'rec123',
}),
domainBuilder.buildAnswer({
challengeId: 'rec456',
}),
domainBuilder.buildAnswer({
challengeId: 'rec789',
}),
],
});

// when
const isComplementaryOnly = certificationAssessment.isComplementaryOnly;

// then
expect(isComplementaryOnly).to.be.false;
});
});

describe('#get isScoringBlockedDueToComplementaryOnlyChallenges', function () {
it('should return true if challenges are only complementary', function () {
//given
const certificationAssessment = domainBuilder.buildCertificationAssessment({
certificationChallenges: [
domainBuilder.buildCertificationChallengeWithType({
challengeId: 'rec123',
certifiableBadgeKey: 'TOTO',
}),
domainBuilder.buildCertificationChallengeWithType({
challengeId: 'rec456',
certifiableBadgeKey: 'TOTO',
}),
domainBuilder.buildCertificationChallengeWithType({
challengeId: 'rec789',
certifiableBadgeKey: 'TOTO',
}),
],
certificationAnswersByDate: [
domainBuilder.buildAnswer({
challengeId: 'rec123',
}),
domainBuilder.buildAnswer({
challengeId: 'rec456',
}),
domainBuilder.buildAnswer({
challengeId: 'rec789',
}),
],
});

// when
const isScoringBlockedDueToComplementaryOnlyChallenges =
certificationAssessment.isScoringBlockedDueToComplementaryOnlyChallenges;

// then
expect(isScoringBlockedDueToComplementaryOnlyChallenges).to.be.true;
});

it('should return false if challenges are not complementary', function () {
//given
const certificationAssessment = domainBuilder.buildCertificationAssessment({
certificationChallenges: [
domainBuilder.buildCertificationChallengeWithType({
challengeId: 'rec123',
certifiableBadgeKey: null,
}),
domainBuilder.buildCertificationChallengeWithType({
challengeId: 'rec456',
certifiableBadgeKey: null,
}),
domainBuilder.buildCertificationChallengeWithType({
challengeId: 'rec789',
certifiableBadgeKey: null,
}),
],
certificationAnswersByDate: [
domainBuilder.buildAnswer({
challengeId: 'rec123',
}),
domainBuilder.buildAnswer({
challengeId: 'rec456',
}),
domainBuilder.buildAnswer({
challengeId: 'rec789',
}),
],
});

// when
const isScoringBlockedDueToComplementaryOnlyChallenges =
certificationAssessment.isScoringBlockedDueToComplementaryOnlyChallenges;

// then
expect(isScoringBlockedDueToComplementaryOnlyChallenges).to.be.false;
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { ChallengeDeneutralized } from '../../../../lib/domain/events/ChallengeD
import { ChallengeNeutralized } from '../../../../lib/domain/events/ChallengeNeutralized.js';
import { _forTestOnly } from '../../../../lib/domain/events/index.js';
import { CertificationAssessment } from '../../../../src/certification/session-management/domain/models/CertificationAssessment.js';
import { AlgorithmEngineVersion } from '../../../../src/certification/shared/domain/models/AlgorithmEngineVersion.js';
import { ABORT_REASONS } from '../../../../src/certification/shared/domain/models/CertificationCourse.js';
import { SESSIONS_VERSIONS } from '../../../../src/certification/shared/domain/models/SessionVersion.js';
import { CertificationComputeError } from '../../../../src/shared/domain/errors.js';
import { AssessmentResult, CertificationResult } from '../../../../src/shared/domain/models/index.js';
import { domainBuilder, expect, sinon } from '../../../test-helper.js';
Expand Down Expand Up @@ -55,7 +55,7 @@ describe('Unit | Domain | Events | handle-certification-rescoring', function ()
it('should save the score with a rejected status', async function () {
// given
const certificationAssessment = domainBuilder.buildCertificationAssessment({
version: SESSIONS_VERSIONS.V3,
version: AlgorithmEngineVersion.V3,
});
const abortedCertificationCourse = domainBuilder.buildCertificationCourse({
abortReason: ABORT_REASONS.CANDIDATE,
Expand Down Expand Up @@ -91,7 +91,7 @@ describe('Unit | Domain | Events | handle-certification-rescoring', function ()
it('should save the score with a rejected status and cancel the certification course', async function () {
// given
const certificationAssessment = domainBuilder.buildCertificationAssessment({
version: SESSIONS_VERSIONS.V3,
version: AlgorithmEngineVersion.V3,
});

const abortedCertificationCourse = domainBuilder.buildCertificationCourse({
Expand Down Expand Up @@ -142,7 +142,7 @@ describe('Unit | Domain | Events | handle-certification-rescoring', function ()
// given
const certificationCourseStartDate = new Date('2022-01-01');
const certificationAssessment = domainBuilder.buildCertificationAssessment({
version: SESSIONS_VERSIONS.V3,
version: AlgorithmEngineVersion.V3,
});

const abortedCertificationCourse = domainBuilder.buildCertificationCourse({
Expand Down Expand Up @@ -183,7 +183,7 @@ describe('Unit | Domain | Events | handle-certification-rescoring', function ()
// given
const certificationCourseStartDate = new Date('2022-01-01');
const certificationAssessment = domainBuilder.buildCertificationAssessment({
version: SESSIONS_VERSIONS.V3,
version: AlgorithmEngineVersion.V3,
});

const abortedCertificationCourse = domainBuilder.buildCertificationCourse({
Expand Down Expand Up @@ -221,7 +221,7 @@ describe('Unit | Domain | Events | handle-certification-rescoring', function ()
const certificationCourseStartDate = new Date('2022-01-01');
// given
const certificationAssessment = domainBuilder.buildCertificationAssessment({
version: SESSIONS_VERSIONS.V3,
version: AlgorithmEngineVersion.V3,
});

const abortedCertificationCourse = domainBuilder.buildCertificationCourse({
Expand Down Expand Up @@ -748,5 +748,44 @@ describe('Unit | Domain | Events | handle-certification-rescoring', function ()
expect(assessmentResultRepository.save).to.have.been.calledOnce;
});
});

context('when assessment in only about complementary certification', function () {
it('should return', async function () {
// given
const event = new ChallengeNeutralized({ certificationCourseId: 1, juryId: 7 });
const certificationAssessment = new CertificationAssessment({
id: 123,
userId: 123,
certificationCourseId: 789,
createdAt: new Date('2020-01-01'),
completedAt: new Date('2020-01-01'),
state: CertificationAssessment.states.STARTED,
version: AlgorithmEngineVersion.V2,
certificationChallenges: [
domainBuilder.buildCertificationChallengeWithType({ certifiableBadgeKey: 'TOTO' }),
domainBuilder.buildCertificationChallengeWithType({ certifiableBadgeKey: 'TOTO' }),
],
certificationAnswersByDate: ['answer'],
});
certificationAssessmentRepository.getByCertificationCourseId
.withArgs({ certificationCourseId: 1 })
.resolves(certificationAssessment);

// when
await handleCertificationRescoring({
event,
assessmentResultRepository,
certificationAssessmentRepository,
competenceMarkRepository,
scoringCertificationService,
certificationEvaluationServices,
certificationCourseRepository,
});

// then
expect(certificationEvaluationServices.handleV2CertificationScoring).to.not.have.been.called;
expect(assessmentResultRepository.save).to.not.have.been.called;
});
});
});
});

0 comments on commit fc8f3ae

Please sign in to comment.