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] Bloquer la finalisation de session selon certaines conditions sur Pix Certif (PIX-14717). #10473

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 @@ -19,6 +19,13 @@ export default class SessionParametersController extends Controller {
return this.certificationCandidates.some(({ isLinked }) => isLinked);
}

get isSessionFinalizationTemporarilyBlocked() {
return (
this.certificationCandidates.some((candidate) => candidate.hasOnlyComplementarySubscription) &&
this.sessionManagement.version === 3
);
}

@action
async showSessionIdTooltip() {
await navigator.clipboard.writeText(this.session.id);
Expand Down
6 changes: 6 additions & 0 deletions certif/app/models/certification-candidate.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,10 @@ export default class CertificationCandidate extends Model {
const hasCleaSubscription = this.subscriptions.some((sub) => sub.isClea(centerHabilitations));
return hasCoreSubscription && hasCleaSubscription;
}

get hasOnlyComplementarySubscription() {
const hasCoreSubscription = this.subscriptions.some((sub) => sub.isCore);
const hasComplementarySubscription = this.subscriptions.some((sub) => sub.isComplementary);
return !hasCoreSubscription && hasComplementarySubscription;
Comment on lines +63 to +65
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proposition de simplification

    return this.subscriptions.every((sub) => sub.isComplementary);

}
}
4 changes: 4 additions & 0 deletions certif/app/models/subscription.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ export default class SubscriptionModel extends Model {
return this.type === SUBSCRIPTION_TYPES.CORE;
}

get isComplementary() {
return this.type === SUBSCRIPTION_TYPES.COMPLEMENTARY;
}

isClea(centerHabilitations) {
const matchingHabilitation = centerHabilitations.find(
(habilitation) => habilitation.id === this.complementaryCertificationId,
Expand Down
34 changes: 18 additions & 16 deletions certif/app/templates/authenticated/sessions/details/parameters.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -121,27 +121,29 @@
</div>

<div class="session-details-buttons">
<PixButtonLink
@route="authenticated.sessions.update"
@model={{this.session.id}}
aria-label={{t "pages.sessions.detail.parameters.actions.update" sessionId=this.session.id}}
>
{{t "common.actions.update"}}
</PixButtonLink>
{{#if this.sessionHasStarted}}
<PixButtonLink @route="authenticated.sessions.update" @model={{this.session.id}}>
{{t "common.actions.update"}}
</PixButtonLink>
{{#if this.sessionManagement.isFinalized}}
{{#if this.isSessionFinalizationTemporarilyBlocked}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cette suite d'imbrications et d'enchainements logiques au niveau templating me fait dire que l'on devrait aller vers de la separation de composants / refacto des conditions

<p class="session-details-row__session-finalized-warning">
{{t "pages.sessions.detail.parameters.finalization-info"}}
{{t "pages.sessions.detail.parameters.finalization.temporarily-blocked"}}
</p>
{{else}}
<PixButtonLink @route="authenticated.sessions.finalize" @model={{this.session.id}} class="push-right">
{{t "pages.sessions.detail.parameters.actions.finalizing"}}
</PixButtonLink>
{{#if this.sessionManagement.isFinalized}}
<p class="session-details-row__session-finalized-warning">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Les differentes class sont pas forcement coherentes, et pas super BEM. L'historique du fichier aide certes pas mais ca renforce ma suggestion de decoupage ci-dessus :)

{{t "pages.sessions.detail.parameters.finalization-info"}}
</p>
{{else}}
<PixButtonLink @route="authenticated.sessions.finalize" @model={{this.session.id}} class="push-right">
{{t "pages.sessions.detail.parameters.actions.finalizing"}}
</PixButtonLink>
{{/if}}
{{/if}}
{{else}}
<PixButtonLink
@route="authenticated.sessions.update"
@model={{this.session.id}}
aria-label={{t "pages.sessions.detail.parameters.actions.update" sessionId=this.session.id}}
>
{{t "common.actions.update"}}
</PixButtonLink>
{{/if}}
</div>

Expand Down
59 changes: 59 additions & 0 deletions certif/tests/acceptance/session-details-parameters-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import { setupIntl } from 'ember-intl/test-support';
import { setupApplicationTest } from 'ember-qunit';
import { CREATED, FINALIZED } from 'pix-certif/models/session-management';
import { SUBSCRIPTION_TYPES } from 'pix-certif/models/subscription';
import { module, test } from 'qunit';

import { authenticateSession } from '../helpers/test-init';
Expand Down Expand Up @@ -85,6 +86,64 @@ module('Acceptance | Session Details Parameters', function (hooks) {
.exists();
});

module('when the session version is 3 and candidates have been enrolled for a complementary course', function () {
test('it should temporarily block the finalise button', async function (assert) {
// given
const allowedCertificationCenterAccess = server.create('allowed-certification-center-access', {
isAccessBlockedCollege: false,
isAccessBlockedLycee: false,
isAccessBlockedAEFE: false,
isAccessBlockedAgri: false,
isV3Pilot: true,
habilitations: [
{
id: 123,
label: 'Pix+Droit',
},
],
});
certificationPointOfContact = server.create('certification-point-of-contact', {
firstName: 'Buffy',
lastName: 'Summers',
allowedCertificationCenterAccesses: [allowedCertificationCenterAccess],
pixCertifTermsOfServiceAccepted: true,
});
await authenticateSession(certificationPointOfContact.id);
const sessionCreated = server.create('session-enrolment', {
id: 123,
status: CREATED,
certificationCenterId: allowedCertificationCenterAccess.id,
});
const complementarySubscription = server.create('subscription', {
type: SUBSCRIPTION_TYPES.COMPLEMENTARY,
complementaryCertificationId: 123,
});
server.create('certification-candidate', {
isLinked: true,
subscriptions: [complementarySubscription],
sessionId: sessionCreated.id,
});
server.create('session-management', {
id: sessionCreated.id,
status: CREATED,
version: 3,
});

// when
const screen = await visit(`/sessions/${sessionCreated.id}`);

// then
assert.dom(screen.queryByRole('button', { name: 'Finaliser la session' })).doesNotExist();
assert
.dom(
screen.getByText(
'Cette session ne peut pas être finalisée pour le moment. Les équipes de Pix travaillent au déblocage de la finalisation.',
),
)
.exists();
});
});

module('when the session is not finalized', function () {
module('when the session is CREATED', function () {
test('it should not display the finalize button if no candidate has joined the session', async function (assert) {
Expand Down
74 changes: 74 additions & 0 deletions certif/tests/unit/models/certification-candidate-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,80 @@ module('Unit | Model | certification-candidate', function (hooks) {
});
});

module('#get hasOnlyComplementarySubscription', function () {
module('when candidate has only one complementary subscription', function () {
test('should return true', function (assert) {
// given
// when
const store = this.owner.lookup('service:store');
const habilitations = [
{
id: 123,
label: 'Certif Pix+Droit',
key: 'DROIT',
},
];
const complementarySubscription = store.createRecord('subscription', {
type: SUBSCRIPTION_TYPES.COMPLEMENTARY,
complementaryCertificationId: habilitations[0].id,
});
const candidate = store.createRecord('certification-candidate', {
subscriptions: [complementarySubscription],
});

// then
assert.true(candidate.hasOnlyComplementarySubscription);
});
});

module('when candidate has a core subscription', function () {
test('should return false', function (assert) {
// given
// when
const store = this.owner.lookup('service:store');
const coreSubscription = store.createRecord('subscription', {
type: SUBSCRIPTION_TYPES.CORE,
complementaryCertificationId: null,
});
const candidate = store.createRecord('certification-candidate', {
subscriptions: [coreSubscription],
});

// then
assert.false(candidate.hasOnlyComplementarySubscription);
});
});

module('when candidate has a clea subscription', function () {
test('should return false', function (assert) {
// given
// when
const habilitations = [
{
id: 123,
label: 'Certif CLEA',
key: COMPLEMENTARY_KEYS.CLEA,
},
];
const store = this.owner.lookup('service:store');
const coreSubscription = store.createRecord('subscription', {
type: SUBSCRIPTION_TYPES.CORE,
complementaryCertificationId: null,
});
const cleaSubscription = store.createRecord('subscription', {
type: SUBSCRIPTION_TYPES.COMPLEMENTARY,
complementaryCertificationId: habilitations[0].id,
});
const candidate = store.createRecord('certification-candidate', {
subscriptions: [coreSubscription, cleaSubscription],
});

// then
assert.false(candidate.hasOnlyComplementarySubscription);
});
});
});

function _pickModelData(certificationCandidate) {
return pick(certificationCandidate, [
'firstName',
Expand Down
43 changes: 43 additions & 0 deletions certif/tests/unit/models/subscription-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,47 @@ module('Unit | Model | subscription', function (hooks) {
assert.false(isCore);
});
});

module('get isComplementary', function () {
module('when subscription is COMPLEMENTARY', function () {
test('it should return true', function (assert) {
// given
const store = this.owner.lookup('service:store');
const habilitations = [
{
id: 123,
label: 'Pix+Droit',
key: 'DROIT',
},
];
const complementarySubscription = store.createRecord('subscription', {
type: SUBSCRIPTION_TYPES.COMPLEMENTARY,
complementaryCertificationId: habilitations[0].id,
});

// when
const isComplementary = complementarySubscription.isComplementary;

// then
assert.true(isComplementary);
});
});

module('when subscription is not COMPLEMENTARY', function () {
test('it should return false', function (assert) {
// given
const store = this.owner.lookup('service:store');
const coreSubscription = store.createRecord('subscription', {
type: SUBSCRIPTION_TYPES.CORE,
complementaryCertificationId: null,
});

// when
const isComplementary = coreSubscription.isComplementary;

// then
assert.false(isComplementary);
});
});
});
});
3 changes: 3 additions & 0 deletions certif/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,9 @@
"finalizing": "Finalise the session",
"update": "Edit the details for session {sessionId}"
},
"finalization": {
"temporarily-blocked": "This session cannot be finalised at the moment. The Pix teams are working to unblock the finalization."
},
"finalization-info": "The finalisation information for the session has already been transmitted to Pix.",
"password": {
"copy-password": "Copy the invigilator’s session password",
Expand Down
3 changes: 3 additions & 0 deletions certif/translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,9 @@
"finalizing": "Finaliser la session",
"update": "Modifier les informations de la session {sessionId}"
},
"finalization": {
"temporarily-blocked": "Cette session ne peut pas être finalisée pour le moment. Les équipes de Pix travaillent au déblocage de la finalisation."
},
"finalization-info": "Les informations de finalisation de la session ont déjà été transmises aux équipes de Pix.",
"password": {
"copy-password": "Copier le mot de passe de session pour le surveillant",
Expand Down
Loading